diff --git a/17/umbraco-cms/.gitbook.yaml b/17/umbraco-cms/.gitbook.yaml new file mode 100644 index 00000000000..0683e8964e1 --- /dev/null +++ b/17/umbraco-cms/.gitbook.yaml @@ -0,0 +1,148 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/configuration: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/styles: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/plugins: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/blocks: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/change-rich-text-editor-ui: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md + customizing/development-flow/typescript-setup: customizing/development-flow/README.md + customizing/foundation/working-with-data: customizing/foundation/README.md + customizing/foundation/working-with-data/context-api: customizing/foundation/context-api/README.md + customizing/foundation/working-with-data/repositories: customizing/foundation/repositories.md + customizing/foundation/working-with-data/states: customizing/foundation/states.md + customizing/foundation/working-with-data/store: customizing/foundation/README.md + reference/notifications/editormodel-notifications/customizing-the-links-box: reference/notifications/editormodel-notifications/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md + tutorials/creating-a-custom-dashboard: tutorials/creating-a-custom-dashboard/README.md + extending/property-editors/declaring-your-property-editor: tutorials/creating-a-property-editor/README.md + reference/management/services/create-a-new-user: reference/management/using-services/userservice.md + reference/management/services/auditservice: reference/management/README.md + reference/management/services/contentservice: reference/management/README.md + reference/management/services/contenttypeservice: reference/management/README.md + reference/management/services/contenttypeservice/retrieving-content-type-containers: reference/management/using-services/contenttypeservice.md + reference/management/services/datatypeservice: reference/management/README.md + reference/management/services/domainservice: reference/management/README.md + reference/management/services/entityservice: reference/management/README.md + reference/management/services/externalloginservice: reference/management/README.md + reference/management/services/fileservice: reference/management/README.md + reference/management/services/localizationservice: reference/management/README.md + reference/management/services/macroservice: reference/management/README.md + reference/management/services/membergroupservice: reference/management/README.md + reference/management/services/memberservice: reference/management/README.md + reference/management/services/membertypeservice: reference/management/README.md + reference/management/services/notificationservice: reference/management/README.md + reference/management/services/packagingservice: reference/management/README.md + reference/management/services/publicaccessservice: reference/management/README.md + reference/management/services/redirecturlservice: reference/management/README.md + reference/management/services/serverregistrationservice: reference/management/README.md + reference/management/services/tagservice: reference/management/README.md + reference/management/services/textservice: reference/management/README.md + reference/management/services/userservice: reference/management/using-services/userservice.md + reference/management/models: reference/management/README.md + reference/management/models/content: reference/management/README.md + reference/management/models/contenttype: reference/management/README.md + reference/management/models/datatype: reference/management/README.md + reference/management/models/dictionaryitem: reference/management/README.md + reference/management/models/language: reference/management/README.md + reference/management/models/media: reference/management/README.md + reference/management/models/mediatype: reference/management/README.md + reference/management/models/relation: reference/management/README.md + reference/management/models/relationtype: reference/management/README.md + reference/management/models/serverregistration: reference/management/README.md + reference/management/models/template: reference/management/README.md + reference/management/services: reference/management/using-services/README.md + reference/management/services/consentservice: reference/management/using-services/consentservice.md + reference/management/services/mediaservice: reference/management/using-services/mediaservice.md + reference/management/services/relationservice: reference/management/using-services/relationservice.md + reference/management/services/contentservice/create-content-programmatically: reference/management/using-services/contentservice.md + reference/management/services/create-content-programmatically: reference/management/using-services/contentservice.md + reference/management/services/contenttypeservice/retrieving-content-types: reference/management/using-services/contenttypeservice.md + reference/management/services/retrieving-content-types: reference/management/using-services/contenttypeservice.md + reference/management/services/localizationservice/retrieving-languages: reference/management/using-services/localizationservice.md + reference/management/services/retrieving-languages: reference/management/using-services/localizationservice.md + reference/management/services/managing-users: reference/management/using-services/userservice.md + reference/management/services/userservice/create-a-new-user: reference/management/using-services/userservice.md + reference/angular: customizing/ui-library.md + reference/angular/directives: customizing/ui-library.md + reference/angular/directives/umbproperty: customizing/ui-library.md + reference/angular/directives/umbloadindicator: customizing/ui-library.md + reference/angular/directives/umblayoutselector: customizing/ui-library.md + reference/angular/services: customizing/ui-library.md + reference/angular/services/editorservice: customizing/ui-library.md + reference/angular/services/eventsservice: customizing/ui-library.md + reference/angular/services/eventsservice/changetitle: customizing/ui-library.md + extending-backoffice/content-apps: customizing/extending-overview/extension-types/workspaces/workspace-views.md + extending-backoffice/localization: customizing/extending-overview/extension-types/localization.md + extending/ui-library: customizing/ui-library.md + extending/backoffice-ui-api-documentation: customizing/ui-library.md + reference/configuration/richtexteditorsettings: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md + extending-backoffice/section-trees/trees/tree-actions: customizing/extending-overview/extending-types/entity-actions.md + extending/macro-parameter-editors: reference/templating/macros.md + extending/health-check/guides/macroerrors: reference/templating/macros.md + fundamentals/design/partial-view-macro-files: reference/templating/macros.md + reference/templating/macros/managing-macros: reference/templating/macros.md + reference/templating/macros/partial-view-macros: reference/templating/macros.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/build-your-own-editor: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/add-value-programmatically: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/configuring-the-grid-layout-datatype: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/settings-and-styles: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/build-your-own-editor: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/render-grid-in-template: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/grid-layout-best-practices: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/grid-layout/grid-editors/what-are-grid-layouts: fundamentals/backoffice/property-editors/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md + reference/notifications/contentypeservice-notifications: reference/notifications/README.md + reference/notifications/datatypeservice-notifications: reference/notifications/README.md + reference/notifications/fileservice-notifications: reference/notifications/README.md + reference/notifications/localizationservice-notifications: reference/notifications/README.md + reference/notifications/mediatypeservice-notifications: reference/notifications/README.md + reference/notifications/membertypeservice-notifications: reference/notifications/README.md + reference/notifications/relationservice-notifications: reference/notifications/README.md + tutorials/editors-manual/working-with-content/rich-text-editor: tutorials/editors-manual/working-with-content.md + fundamentals/backoffice/content-templates: fundamentals/backoffice/document-blueprints.md + reference/configuration/runtimeminificationsettings: reference/configuration/README.md + reference/routing/umbraco-api-controllers/authorization: reference/routing/umbraco-api-controllers/README.md + reference/routing/umbraco-api-controllers/routing: reference/routing/umbraco-api-controllers/README.md + reference/notifications/sendingallowedchildrennotifications: reference/content-type-filters.md + extending/property-editors/package-manifest: customizing/umbraco-package.md + fundamentals/backoffice/infinite-editing: fundamentals/backoffice/sidebar.md + extending/backoffice-tours: extending/build-on-umbraco-functionality.md + tutorials/creating-a-backoffice-tour: tutorials/overview.md + extending/packages/types-of-packages: extending/packages/README.md + reference/configuration/nucachesettings: reference/configuration/cache-settings.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-styles: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/styles.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-plugins: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/plugins.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-blocks: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor-tinymce/blocks.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration: reference/umbraco-flavored-markdown.md + customizing/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md + tutorials/creating-and-distributing-a-package: extending/packages/creating-a-package.md + fundamentals/design/templates/named-sections: fundamentals/design/templates/README.md + tutorials/custom-error-pages: tutorials/custom-error-page.md + reference/events/contentservice-events: reference/notifications/contentservice-notifications.md + reference/configuration-for-umbraco-7-and-8/webconfig: reference/configuration/README.md + fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/build-custom-view-for-blocks: tutorials/creating-custom-views-for-blocklist.md + fundamentals/backoffice/property-editors/built-in-property-editors/rich-text-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md + fundamentals/backoffice/property-editors/built-in-property-editors/nested-content: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md + fundamentals/backoffice/property-editors/built-in-property-editors/block-list-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md + extending/ui-documentation: customizing/README.md + extending/section-trees/sections: umbraco-cms/customizing/extending-overview/extension-types/sections/section.md + extending/property-editors: customizing/property-editors/README.md + extending/language-files/ui-localization: customizing/foundation/localization.md + extending/dashboards: customizing/extending-overview/extension-types/dashboard.md + extending/customize-the-editing-experience: customizing/README.md + extending/customize-backoffice/vite-package-setup: customizing/development-flow/vite-package-setup.md + extending/customize-backoffice: customizing/README.md + extending/content-apps: customizing/extending-overview/extension-types/workspaces/workspace-views.md + extending/backoffice-setup/extension-types: customizing/extending-overview/extension-types/README.md + customizing/extending-overview/extension-registry/extension-registry: customizing/extending-overview/extension-registry/register-extensions.md diff --git a/17/umbraco-cms/.gitbook/assets/Additional_Info (1).jpg b/17/umbraco-cms/.gitbook/assets/Additional_Info (1).jpg new file mode 100644 index 00000000000..72a2929b890 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Additional_Info (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Additional_Info (2).jpg b/17/umbraco-cms/.gitbook/assets/Additional_Info (2).jpg new file mode 100644 index 00000000000..72a2929b890 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Additional_Info (2).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Additional_Info.jpg b/17/umbraco-cms/.gitbook/assets/Additional_Info.jpg new file mode 100644 index 00000000000..72a2929b890 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Additional_Info.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Additional_Info_V16.png b/17/umbraco-cms/.gitbook/assets/Additional_Info_V16.png new file mode 100644 index 00000000000..24f1f3326c7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Additional_Info_V16.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Canvas_tab (1).png b/17/umbraco-cms/.gitbook/assets/Canvas_tab (1).png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Canvas_tab (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Canvas_tab (2).png b/17/umbraco-cms/.gitbook/assets/Canvas_tab (2).png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Canvas_tab (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Canvas_tab.png b/17/umbraco-cms/.gitbook/assets/Canvas_tab.png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Canvas_tab.png differ diff --git a/17/umbraco-cms/.gitbook/assets/ContentPicker-data-type-definition.png b/17/umbraco-cms/.gitbook/assets/ContentPicker-data-type-definition.png new file mode 100644 index 00000000000..4079d60ffc6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/ContentPicker-data-type-definition.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_LaunchJson_file.jpg b/17/umbraco-cms/.gitbook/assets/Create_LaunchJson_file.jpg new file mode 100644 index 00000000000..0ce06b712d2 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_LaunchJson_file.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality (1).png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality (1).png new file mode 100644 index 00000000000..2ffb4829d22 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality.png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality.png new file mode 100644 index 00000000000..2ffb4829d22 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data (1).png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data (1).png new file mode 100644 index 00000000000..ebc88d8d4fb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data.png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data.png new file mode 100644 index 00000000000..ebc88d8d4fb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_gettting_data.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list (1).png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list (1).png new file mode 100644 index 00000000000..2393d1f4590 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list.png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list.png new file mode 100644 index 00000000000..2393d1f4590 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled (1).png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled (1).png new file mode 100644 index 00000000000..41774b290b1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled.png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled.png new file mode 100644 index 00000000000..41774b290b1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table (1).png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table (1).png new file mode 100644 index 00000000000..71dc772189f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table.png b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table.png new file mode 100644 index 00000000000..71dc772189f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_dashboard_functionality_users_list_ui_styled_table.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript (1).png b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript (1).png new file mode 100644 index 00000000000..298fc34e257 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript.png b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript.png new file mode 100644 index 00000000000..298fc34e257 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Typescript.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla (1).png b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla (1).png new file mode 100644 index 00000000000..d132d1b4d23 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla.png b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla.png new file mode 100644 index 00000000000..d132d1b4d23 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Create_first_extension_Vanilla.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Docs_tab (1).png b/17/umbraco-cms/.gitbook/assets/Docs_tab (1).png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Docs_tab (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Docs_tab (2).png b/17/umbraco-cms/.gitbook/assets/Docs_tab (2).png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Docs_tab (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Docs_tab.png b/17/umbraco-cms/.gitbook/assets/Docs_tab.png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Docs_tab.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png new file mode 100644 index 00000000000..3521daba379 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Dashboards.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png new file mode 100644 index 00000000000..5524b73c767 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Health_Checks.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png new file mode 100644 index 00000000000..126a7bb65a1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Packages.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png new file mode 100644 index 00000000000..555d76dfbee Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Property_Editors.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png new file mode 100644 index 00000000000..c313d797d13 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png new file mode 100644 index 00000000000..b9010a07979 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (1).png new file mode 100644 index 00000000000..07e0d5c35eb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (2).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (2).png new file mode 100644 index 00000000000..07e0d5c35eb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1).png new file mode 100644 index 00000000000..07e0d5c35eb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice.png new file mode 100644 index 00000000000..07e0d5c35eb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Code.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Code.png new file mode 100644 index 00000000000..6258bb83e76 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Code.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Data.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Data.png new file mode 100644 index 00000000000..635ea063b60 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Data.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Design.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Design.png new file mode 100644 index 00000000000..b3ed5209357 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Design.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup (1).png new file mode 100644 index 00000000000..7ec0cf1d7b5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup.png new file mode 100644 index 00000000000..7ec0cf1d7b5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Fundamentals_Setup.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png new file mode 100644 index 00000000000..b10aa4d8651 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Composing.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png new file mode 100644 index 00000000000..56e75d65963 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Controllers.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png new file mode 100644 index 00000000000..4ac0bbf95a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Custom_Routing.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png new file mode 100644 index 00000000000..ac956eafbbc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Data_Persistence.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png new file mode 100644 index 00000000000..8ea13956765 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Routing.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png new file mode 100644 index 00000000000..724c96c54d3 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Implementation_Services_and_Helpers.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install (1).png new file mode 100644 index 00000000000..01beb93f1e6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png new file mode 100644 index 00000000000..01beb93f1e6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Install.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png new file mode 100644 index 00000000000..7164d6542f9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_API_Documentation.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png new file mode 100644 index 00000000000..41b02fe3c4a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Caching.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png new file mode 100644 index 00000000000..35d43482ffd Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Configuration.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png new file mode 100644 index 00000000000..5790d353ba3 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Notifications.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png new file mode 100644 index 00000000000..61b11658050 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png new file mode 100644 index 00000000000..8529aae789f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Routing_and_Controllers.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching (1).png new file mode 100644 index 00000000000..36feaf25719 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png new file mode 100644 index 00000000000..36feaf25719 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Searching.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png new file mode 100644 index 00000000000..a9bbebbbea0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Security.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png new file mode 100644 index 00000000000..94df11bb19a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Reference_Templating.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png new file mode 100644 index 00000000000..f96fffc1c43 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png new file mode 100644 index 00000000000..45f98513f48 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Basic_Website.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png new file mode 100644 index 00000000000..49a429c95da Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Dashboard.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png new file mode 100644 index 00000000000..f95896c57ef Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Error_Page.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png new file mode 100644 index 00000000000..fb540e90782 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Property_Editor.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png new file mode 100644 index 00000000000..8b0c842229f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Custom_Views_Block_List.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png new file mode 100644 index 00000000000..3f678967f20 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Google_Authentification.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png new file mode 100644 index 00000000000..66dc300073f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Member_Reg_and_login.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup (1).png new file mode 100644 index 00000000000..a6e56cde534 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png new file mode 100644 index 00000000000..a6e56cde534 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_MultiSite_Setup.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png new file mode 100644 index 00000000000..92cc76d753f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Multilingual_Website.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png new file mode 100644 index 00000000000..ccffbc3c872 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_Umbraco_Forms_and_Zapier.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit (1).png new file mode 100644 index 00000000000..aed96f1fd6a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png new file mode 100644 index 00000000000..aed96f1fd6a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Cloud_Setup.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Cloud_Setup.png new file mode 100644 index 00000000000..0dad8ed536e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Cloud_Setup.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Commerce_How_to_Guide.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Commerce_How_to_Guide.png new file mode 100644 index 00000000000..bdcd0b3f83c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Commerce_How_to_Guide.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install (1).png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install (1).png new file mode 100644 index 00000000000..e4aa739cb56 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png new file mode 100644 index 00000000000..e4aa739cb56 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Dropdown_option.jpg b/17/umbraco-cms/.gitbook/assets/Dropdown_option.jpg new file mode 100644 index 00000000000..8c6c135c273 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Dropdown_option.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Install_Umbraco.jpg b/17/umbraco-cms/.gitbook/assets/Install_Umbraco.jpg new file mode 100644 index 00000000000..88c43ab285e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Install_Umbraco.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Latest_nightly_build_version.jpg b/17/umbraco-cms/.gitbook/assets/Latest_nightly_build_version.jpg new file mode 100644 index 00000000000..341da76534c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Latest_nightly_build_version.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs (1).jpg b/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs (1).jpg new file mode 100644 index 00000000000..68138f7e4b6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs.jpg b/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs.jpg new file mode 100644 index 00000000000..68138f7e4b6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Manage_NuGet_Pkgs.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Manage_Packages.jpg b/17/umbraco-cms/.gitbook/assets/Manage_Packages.jpg new file mode 100644 index 00000000000..9ff2c8538dc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Manage_Packages.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Marketplace.jpg b/17/umbraco-cms/.gitbook/assets/Marketplace.jpg new file mode 100644 index 00000000000..e9d31ab959e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Marketplace.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png b/17/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png new file mode 100644 index 00000000000..14492e61ab3 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/ModelsBuilderDisabledOnProduction.png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewFeed_Details.jpg b/17/umbraco-cms/.gitbook/assets/NewFeed_Details.jpg new file mode 100644 index 00000000000..5ce96af75da Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewFeed_Details.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditor (1).png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditor (1).png new file mode 100644 index 00000000000..b7803bdf34b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditor (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditor.png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditor.png new file mode 100644 index 00000000000..b7803bdf34b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditor.png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons (1).png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons (1).png new file mode 100644 index 00000000000..1da56df1786 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons.png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons.png new file mode 100644 index 00000000000..1da56df1786 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorButtons.png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions (1).png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions (1).png new file mode 100644 index 00000000000..fa8291c3905 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions.png b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions.png new file mode 100644 index 00000000000..fa8291c3905 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NewPropertyEditorSuggestions.png differ diff --git a/17/umbraco-cms/.gitbook/assets/New_Project.jpg b/17/umbraco-cms/.gitbook/assets/New_Project.jpg new file mode 100644 index 00000000000..0666959592a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/New_Project.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/NuGet_NewFeed.jpg b/17/umbraco-cms/.gitbook/assets/NuGet_NewFeed.jpg new file mode 100644 index 00000000000..e17dee522b9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/NuGet_NewFeed.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (1).jpg b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (1).jpg new file mode 100644 index 00000000000..748293bccb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (2).jpg b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (2).jpg new file mode 100644 index 00000000000..748293bccb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1) (2).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1).jpg b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1).jpg new file mode 100644 index 00000000000..748293bccb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings.jpg b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings.jpg new file mode 100644 index 00000000000..748293bccb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Package-Manager-Settings.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217 (1).png b/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217 (1).png new file mode 100644 index 00000000000..9e2ea36a5f8 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217.png b/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217.png new file mode 100644 index 00000000000..9e2ea36a5f8 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Pasted image 20230525192217.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Prompt_Menu.jpg b/17/umbraco-cms/.gitbook/assets/Prompt_Menu.jpg new file mode 100644 index 00000000000..e700d4609b9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Prompt_Menu.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG b/17/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG new file mode 100644 index 00000000000..a0d6f1abbb9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/ReferencedDataTypes.PNG differ diff --git a/17/umbraco-cms/.gitbook/assets/Register_Nightly_Feed.jpg b/17/umbraco-cms/.gitbook/assets/Register_Nightly_Feed.jpg new file mode 100644 index 00000000000..bd549030ecc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Register_Nightly_Feed.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed.jpg b/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed.jpg new file mode 100644 index 00000000000..68701876301 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed_version.jpg b/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed_version.jpg new file mode 100644 index 00000000000..9b60bb59f21 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Rider_Nightly_Feed_version.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Screenshot 2025-06-04 at 12.45.05.png b/17/umbraco-cms/.gitbook/assets/Screenshot 2025-06-04 at 12.45.05.png new file mode 100644 index 00000000000..3462128b1a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Screenshot 2025-06-04 at 12.45.05.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Solution_Explorer.png b/17/umbraco-cms/.gitbook/assets/Solution_Explorer.png new file mode 100644 index 00000000000..254eb8d89be Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Solution_Explorer.png differ diff --git a/17/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png b/17/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png new file mode 100644 index 00000000000..f6379dc05f6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/TemplatedCannotBeEditedWhenRuntimeIsProduction.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png b/17/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png new file mode 100644 index 00000000000..10ef4a25841 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Top_hero_for_com_1500x500px2.png differ diff --git a/17/umbraco-cms/.gitbook/assets/UUI.jpg b/17/umbraco-cms/.gitbook/assets/UUI.jpg new file mode 100644 index 00000000000..28a397b8e2f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/UUI.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Hero_1665x438px.jpg b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Hero_1665x438px.jpg new file mode 100644 index 00000000000..00e1e766fd8 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Hero_1665x438px.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - SoMe_1200x628px.jpg b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - SoMe_1200x628px.jpg new file mode 100644 index 00000000000..222ddb45785 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - SoMe_1200x628px.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Thumbnail_898x598px.jpg b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Thumbnail_898x598px.jpg new file mode 100644 index 00000000000..2037767fcf5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Umbraco 15 - Release - Thumbnail_898x598px.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Umbraco 16 - Hero.jpg b/17/umbraco-cms/.gitbook/assets/Umbraco 16 - Hero.jpg new file mode 100644 index 00000000000..3cee1bf8f61 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Umbraco 16 - Hero.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg b/17/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg new file mode 100644 index 00000000000..71aafdbe493 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Using_Dictionary_Value.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/VS-Package-Sources (1).jpg b/17/umbraco-cms/.gitbook/assets/VS-Package-Sources (1).jpg new file mode 100644 index 00000000000..d29f5cc865b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/VS-Package-Sources (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/VS-Package-Sources.jpg b/17/umbraco-cms/.gitbook/assets/VS-Package-Sources.jpg new file mode 100644 index 00000000000..d29f5cc865b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/VS-Package-Sources.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/VS_Code_Explorer.png b/17/umbraco-cms/.gitbook/assets/VS_Code_Explorer.png new file mode 100644 index 00000000000..8a2fb9da115 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/VS_Code_Explorer.png differ diff --git a/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard (1).png b/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard (1).png new file mode 100644 index 00000000000..1a623c467ba Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard.png b/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard.png new file mode 100644 index 00000000000..1a623c467ba Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/Vite_Package_Setup_Dashboard.png differ diff --git a/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (1).png b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (1).png new file mode 100644 index 00000000000..fa519c365bc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (2).png b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (2).png new file mode 100644 index 00000000000..fa519c365bc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10.png b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10.png new file mode 100644 index 00000000000..fa519c365bc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/WeKnowWhatYouEditedLastWeek-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/add-custom-section-v8 (1).png b/17/umbraco-cms/.gitbook/assets/add-custom-section-v8 (1).png new file mode 100644 index 00000000000..d5465050e54 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/add-custom-section-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/add-custom-section-v8.png b/17/umbraco-cms/.gitbook/assets/add-custom-section-v8.png new file mode 100644 index 00000000000..d5465050e54 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/add-custom-section-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/all-users-first-look.png b/17/umbraco-cms/.gitbook/assets/all-users-first-look.png new file mode 100644 index 00000000000..c1f369af340 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/all-users-first-look.png differ diff --git a/17/umbraco-cms/.gitbook/assets/all-users-first-look2.png b/17/umbraco-cms/.gitbook/assets/all-users-first-look2.png new file mode 100644 index 00000000000..1a2a34217db Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/all-users-first-look2.png differ diff --git a/17/umbraco-cms/.gitbook/assets/api-docs-image.png b/17/umbraco-cms/.gitbook/assets/api-docs-image.png new file mode 100644 index 00000000000..215f4191aff Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/api-docs-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/app-pligins-contents.png b/17/umbraco-cms/.gitbook/assets/app-pligins-contents.png new file mode 100644 index 00000000000..c0350372ad7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/app-pligins-contents.png differ diff --git a/17/umbraco-cms/.gitbook/assets/append-step-to-query.png b/17/umbraco-cms/.gitbook/assets/append-step-to-query.png new file mode 100644 index 00000000000..e180bb29a74 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/append-step-to-query.png differ diff --git a/17/umbraco-cms/.gitbook/assets/are-you-hungry.png b/17/umbraco-cms/.gitbook/assets/are-you-hungry.png new file mode 100644 index 00000000000..d3367721f56 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/are-you-hungry.png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice-overview-customizations.png b/17/umbraco-cms/.gitbook/assets/backoffice-overview-customizations.png new file mode 100644 index 00000000000..144ff1379a1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice-overview-customizations.png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice-search-v8 (1).png b/17/umbraco-cms/.gitbook/assets/backoffice-search-v8 (1).png new file mode 100644 index 00000000000..1ab9820f3bc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice-search-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice-search-v8.png b/17/umbraco-cms/.gitbook/assets/backoffice-search-v8.png new file mode 100644 index 00000000000..1ab9820f3bc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice-search-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice-ui-images (1).png b/17/umbraco-cms/.gitbook/assets/backoffice-ui-images (1).png new file mode 100644 index 00000000000..52949da0a85 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice-ui-images (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice-ui-images.png b/17/umbraco-cms/.gitbook/assets/backoffice-ui-images.png new file mode 100644 index 00000000000..52949da0a85 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice-ui-images.png differ diff --git a/17/umbraco-cms/.gitbook/assets/backoffice.png b/17/umbraco-cms/.gitbook/assets/backoffice.png new file mode 100644 index 00000000000..fb407f3e003 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/backoffice.png differ diff --git a/17/umbraco-cms/.gitbook/assets/block-list-image.png b/17/umbraco-cms/.gitbook/assets/block-list-image.png new file mode 100644 index 00000000000..7e2462aff88 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/block-list-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/c-routing-image.png b/17/umbraco-cms/.gitbook/assets/c-routing-image.png new file mode 100644 index 00000000000..6ef562a2139 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/c-routing-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/caching-image.png b/17/umbraco-cms/.gitbook/assets/caching-image.png new file mode 100644 index 00000000000..16c31b7d1fd Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/caching-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (1).png b/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (1).png new file mode 100644 index 00000000000..51b59df68af Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (2).png b/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (2).png new file mode 100644 index 00000000000..51b59df68af Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/changing-languages-v10 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/changing-languages-v10.png b/17/umbraco-cms/.gitbook/assets/changing-languages-v10.png new file mode 100644 index 00000000000..51b59df68af Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/changing-languages-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/code-image.png b/17/umbraco-cms/.gitbook/assets/code-image.png new file mode 100644 index 00000000000..37060e9deb1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/code-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/collection-icon.png b/17/umbraco-cms/.gitbook/assets/collection-icon.png new file mode 100644 index 00000000000..41b58466ad7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/collection-icon.png differ diff --git a/17/umbraco-cms/.gitbook/assets/collection-settings-example-15-1.png b/17/umbraco-cms/.gitbook/assets/collection-settings-example-15-1.png new file mode 100644 index 00000000000..9b989d60176 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/collection-settings-example-15-1.png differ diff --git a/17/umbraco-cms/.gitbook/assets/composing-image.png b/17/umbraco-cms/.gitbook/assets/composing-image.png new file mode 100644 index 00000000000..84114e14334 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/composing-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/consolelog.png b/17/umbraco-cms/.gitbook/assets/consolelog.png new file mode 100644 index 00000000000..ac07082a2e4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/consolelog.png differ diff --git a/17/umbraco-cms/.gitbook/assets/content-picker-query-steps.png b/17/umbraco-cms/.gitbook/assets/content-picker-query-steps.png new file mode 100644 index 00000000000..0204da0e2a6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/content-picker-query-steps.png differ diff --git a/17/umbraco-cms/.gitbook/assets/controllers-image (1).png b/17/umbraco-cms/.gitbook/assets/controllers-image (1).png new file mode 100644 index 00000000000..18d83567ff4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/controllers-image (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/controllers-image.png b/17/umbraco-cms/.gitbook/assets/controllers-image.png new file mode 100644 index 00000000000..18d83567ff4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/controllers-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/create-website-image.png b/17/umbraco-cms/.gitbook/assets/create-website-image.png new file mode 100644 index 00000000000..950d99bb992 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/create-website-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/creating-a-property-editor-trim.png b/17/umbraco-cms/.gitbook/assets/creating-a-property-editor-trim.png new file mode 100644 index 00000000000..5a964fd5215 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/creating-a-property-editor-trim.png differ diff --git a/17/umbraco-cms/.gitbook/assets/creating-package-menu-v9.png b/17/umbraco-cms/.gitbook/assets/creating-package-menu-v9.png new file mode 100644 index 00000000000..da73453c0a6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/creating-package-menu-v9.png differ diff --git a/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8 (1).png b/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8 (1).png new file mode 100644 index 00000000000..6a8e9633af9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8.png b/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8.png new file mode 100644 index 00000000000..6a8e9633af9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/custom-section-alias-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-logviewer.png b/17/umbraco-cms/.gitbook/assets/dashboard-logviewer.png new file mode 100644 index 00000000000..47296f6475e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-logviewer.png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (1).png b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (1).png new file mode 100644 index 00000000000..3f81a1b8dd0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (2).png b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (2).png new file mode 100644 index 00000000000..3f81a1b8dd0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10.png b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10.png new file mode 100644 index 00000000000..3f81a1b8dd0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-translated-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (1).png b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (1).png new file mode 100644 index 00000000000..c5410b1f223 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (2).png b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (2).png new file mode 100644 index 00000000000..c5410b1f223 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10.png b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10.png new file mode 100644 index 00000000000..c5410b1f223 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboard-untranslated-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/dashboards-image.png b/17/umbraco-cms/.gitbook/assets/dashboards-image.png new file mode 100644 index 00000000000..ae820772b31 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dashboards-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/data-flow.svg b/17/umbraco-cms/.gitbook/assets/data-flow.svg new file mode 100644 index 00000000000..e7a8481c17b --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/data-flow.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/data-types-references-v10.png b/17/umbraco-cms/.gitbook/assets/data-types-references-v10.png new file mode 100644 index 00000000000..bc1cddf4a1c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/data-types-references-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/data.png b/17/umbraco-cms/.gitbook/assets/data.png new file mode 100644 index 00000000000..00b9bd36c20 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/data.png differ diff --git a/17/umbraco-cms/.gitbook/assets/datap-image.png b/17/umbraco-cms/.gitbook/assets/datap-image.png new file mode 100644 index 00000000000..33c7e6e117c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/datap-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8 (1).png b/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8 (1).png new file mode 100644 index 00000000000..ac562758a4b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8.png b/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8.png new file mode 100644 index 00000000000..ac562758a4b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/delete-raindrops-on-roses-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/design.png b/17/umbraco-cms/.gitbook/assets/design.png new file mode 100644 index 00000000000..f35e9ca42fd Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/design.png differ diff --git a/17/umbraco-cms/.gitbook/assets/docs-style-hero.png b/17/umbraco-cms/.gitbook/assets/docs-style-hero.png new file mode 100644 index 00000000000..a63f4894788 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/docs-style-hero.png differ diff --git a/17/umbraco-cms/.gitbook/assets/document-references-v9.png b/17/umbraco-cms/.gitbook/assets/document-references-v9.png new file mode 100644 index 00000000000..ff428234d8e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/document-references-v9.png differ diff --git a/17/umbraco-cms/.gitbook/assets/dynamic-templates.zip b/17/umbraco-cms/.gitbook/assets/dynamic-templates.zip new file mode 100644 index 00000000000..305af158943 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/dynamic-templates.zip differ diff --git a/17/umbraco-cms/.gitbook/assets/editorBar-v9.jpg b/17/umbraco-cms/.gitbook/assets/editorBar-v9.jpg new file mode 100644 index 00000000000..3b13ec937c3 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/editorBar-v9.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/embeded-resource-props.png b/17/umbraco-cms/.gitbook/assets/embeded-resource-props.png new file mode 100644 index 00000000000..ee8e0b6a49e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/embeded-resource-props.png differ diff --git a/17/umbraco-cms/.gitbook/assets/embeded-resource.png b/17/umbraco-cms/.gitbook/assets/embeded-resource.png new file mode 100644 index 00000000000..f3ac2e59a1a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/embeded-resource.png differ diff --git a/17/umbraco-cms/.gitbook/assets/embeded-zip-resource.png b/17/umbraco-cms/.gitbook/assets/embeded-zip-resource.png new file mode 100644 index 00000000000..4b85628f1a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/embeded-zip-resource.png differ diff --git a/17/umbraco-cms/.gitbook/assets/empty-package-from-template.png b/17/umbraco-cms/.gitbook/assets/empty-package-from-template.png new file mode 100644 index 00000000000..0a692a5c54e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/empty-package-from-template.png differ diff --git a/17/umbraco-cms/.gitbook/assets/entity-action-collection-menu.svg b/17/umbraco-cms/.gitbook/assets/entity-action-collection-menu.svg new file mode 100644 index 00000000000..d9918b302aa --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/entity-action-collection-menu.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/entity-action-example-content-section.png b/17/umbraco-cms/.gitbook/assets/entity-action-example-content-section.png new file mode 100644 index 00000000000..d94ccac8158 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/entity-action-example-content-section.png differ diff --git a/17/umbraco-cms/.gitbook/assets/entity-action-picker-context-menu.svg b/17/umbraco-cms/.gitbook/assets/entity-action-picker-context-menu.svg new file mode 100644 index 00000000000..6a3daa0be37 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/entity-action-picker-context-menu.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/entity-action-sidebar-context.svg b/17/umbraco-cms/.gitbook/assets/entity-action-sidebar-context.svg new file mode 100644 index 00000000000..5e0e9b44c2d --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/entity-action-sidebar-context.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/entity-action-workspace-menu.svg b/17/umbraco-cms/.gitbook/assets/entity-action-workspace-menu.svg new file mode 100644 index 00000000000..483aededf30 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/entity-action-workspace-menu.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/entity-bulk-action-collection-menu.svg b/17/umbraco-cms/.gitbook/assets/entity-bulk-action-collection-menu.svg new file mode 100644 index 00000000000..71b4e5eb5c2 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/entity-bulk-action-collection-menu.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/entity-user-permissions-ui.png b/17/umbraco-cms/.gitbook/assets/entity-user-permissions-ui.png new file mode 100644 index 00000000000..245a3d3a5b2 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/entity-user-permissions-ui.png differ diff --git a/17/umbraco-cms/.gitbook/assets/error-pages-image.png b/17/umbraco-cms/.gitbook/assets/error-pages-image.png new file mode 100644 index 00000000000..a54961025b6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/error-pages-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/example-of-property-actions (1).jpg b/17/umbraco-cms/.gitbook/assets/example-of-property-actions (1).jpg new file mode 100644 index 00000000000..2e94865f559 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/example-of-property-actions (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/example-of-property-actions.jpg b/17/umbraco-cms/.gitbook/assets/example-of-property-actions.jpg new file mode 100644 index 00000000000..2e94865f559 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/example-of-property-actions.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary (1).png b/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary (1).png new file mode 100644 index 00000000000..041139ba80f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary.png b/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary.png new file mode 100644 index 00000000000..041139ba80f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/extendedWithUiLibrary.png differ diff --git a/17/umbraco-cms/.gitbook/assets/extension-types-backoffice-browser.png b/17/umbraco-cms/.gitbook/assets/extension-types-backoffice-browser.png new file mode 100644 index 00000000000..15450daf901 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/extension-types-backoffice-browser.png differ diff --git a/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree (1).png b/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree (1).png new file mode 100644 index 00000000000..c40ceb25a75 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree.png b/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree.png new file mode 100644 index 00000000000..c40ceb25a75 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favourite-thing-custom-single-node-tree.png differ diff --git a/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8 (1).png b/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8 (1).png new file mode 100644 index 00000000000..c6e99e95dc7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8.png b/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8.png new file mode 100644 index 00000000000..c6e99e95dc7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favourite-things-custom-tree-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8 (1).png b/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8 (1).png new file mode 100644 index 00000000000..c1010a8dda1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8.png b/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8.png new file mode 100644 index 00000000000..c1010a8dda1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/favouritethings-search-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/gitbook1.png b/17/umbraco-cms/.gitbook/assets/gitbook1.png new file mode 100644 index 00000000000..6afebb8db8d Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/gitbook1.png differ diff --git a/17/umbraco-cms/.gitbook/assets/google-auth-image.png b/17/umbraco-cms/.gitbook/assets/google-auth-image.png new file mode 100644 index 00000000000..e3aa84cc8a4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/google-auth-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/granular-user-permissions-ui.png b/17/umbraco-cms/.gitbook/assets/granular-user-permissions-ui.png new file mode 100644 index 00000000000..2b1a223e744 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/granular-user-permissions-ui.png differ diff --git a/17/umbraco-cms/.gitbook/assets/happy-anniversary.png b/17/umbraco-cms/.gitbook/assets/happy-anniversary.png new file mode 100644 index 00000000000..5fea181f52c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/happy-anniversary.png differ diff --git a/17/umbraco-cms/.gitbook/assets/header-app-example-ts (1).png b/17/umbraco-cms/.gitbook/assets/header-app-example-ts (1).png new file mode 100644 index 00000000000..8153d236233 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/header-app-example-ts (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/header-app-example-ts.png b/17/umbraco-cms/.gitbook/assets/header-app-example-ts.png new file mode 100644 index 00000000000..65d2b1a206c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/header-app-example-ts.png differ diff --git a/17/umbraco-cms/.gitbook/assets/header-app-example.png b/17/umbraco-cms/.gitbook/assets/header-app-example.png new file mode 100644 index 00000000000..1ea617940f0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/header-app-example.png differ diff --git a/17/umbraco-cms/.gitbook/assets/header-apps-custom.png b/17/umbraco-cms/.gitbook/assets/header-apps-custom.png new file mode 100644 index 00000000000..85303a20996 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/header-apps-custom.png differ diff --git a/17/umbraco-cms/.gitbook/assets/header-apps.svg b/17/umbraco-cms/.gitbook/assets/header-apps.svg new file mode 100644 index 00000000000..c9054b02e1b --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/header-apps.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/healthchecks-image (1).png b/17/umbraco-cms/.gitbook/assets/healthchecks-image (1).png new file mode 100644 index 00000000000..954ba2acfb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/healthchecks-image (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/healthchecks-image.png b/17/umbraco-cms/.gitbook/assets/healthchecks-image.png new file mode 100644 index 00000000000..954ba2acfb7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/healthchecks-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/help-menu.svg b/17/umbraco-cms/.gitbook/assets/help-menu.svg new file mode 100644 index 00000000000..d5fc6683779 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/help-menu.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/html5up-story.zip b/17/umbraco-cms/.gitbook/assets/html5up-story.zip new file mode 100644 index 00000000000..7effddfb275 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/html5up-story.zip differ diff --git a/17/umbraco-cms/.gitbook/assets/image (1) (1).png b/17/umbraco-cms/.gitbook/assets/image (1) (1).png new file mode 100644 index 00000000000..f7933c19d15 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (1) (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (1).png b/17/umbraco-cms/.gitbook/assets/image (1).png new file mode 100644 index 00000000000..b65b978bf84 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (10).png b/17/umbraco-cms/.gitbook/assets/image (10).png new file mode 100644 index 00000000000..481423e8db6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (10).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (11).png b/17/umbraco-cms/.gitbook/assets/image (11).png new file mode 100644 index 00000000000..eb4330ec76a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (11).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (12).png b/17/umbraco-cms/.gitbook/assets/image (12).png new file mode 100644 index 00000000000..b8e8bf6135c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (12).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (13).png b/17/umbraco-cms/.gitbook/assets/image (13).png new file mode 100644 index 00000000000..7fec9b4d8d0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (13).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (14).png b/17/umbraco-cms/.gitbook/assets/image (14).png new file mode 100644 index 00000000000..41aa7327446 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (14).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (15).png b/17/umbraco-cms/.gitbook/assets/image (15).png new file mode 100644 index 00000000000..4c846b75695 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (15).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (16).png b/17/umbraco-cms/.gitbook/assets/image (16).png new file mode 100644 index 00000000000..78e18ac9371 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (16).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (17).png b/17/umbraco-cms/.gitbook/assets/image (17).png new file mode 100644 index 00000000000..57a6ac8ccd1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (17).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (18).png b/17/umbraco-cms/.gitbook/assets/image (18).png new file mode 100644 index 00000000000..eaec414510d Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (18).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (19).png b/17/umbraco-cms/.gitbook/assets/image (19).png new file mode 100644 index 00000000000..0c35835d207 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (19).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (2).png b/17/umbraco-cms/.gitbook/assets/image (2).png new file mode 100644 index 00000000000..1b3afc7f2cd Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (20).png b/17/umbraco-cms/.gitbook/assets/image (20).png new file mode 100644 index 00000000000..7d9e34527fc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (20).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (21).png b/17/umbraco-cms/.gitbook/assets/image (21).png new file mode 100644 index 00000000000..7d9e34527fc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (21).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (22).png b/17/umbraco-cms/.gitbook/assets/image (22).png new file mode 100644 index 00000000000..12d9deb094f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (22).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (23).png b/17/umbraco-cms/.gitbook/assets/image (23).png new file mode 100644 index 00000000000..9e9a5151407 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (23).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (24).png b/17/umbraco-cms/.gitbook/assets/image (24).png new file mode 100644 index 00000000000..3a8efa8e1ab Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (24).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (25).png b/17/umbraco-cms/.gitbook/assets/image (25).png new file mode 100644 index 00000000000..f7e83984290 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (25).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (26).png b/17/umbraco-cms/.gitbook/assets/image (26).png new file mode 100644 index 00000000000..8861f880c08 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (26).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (27).png b/17/umbraco-cms/.gitbook/assets/image (27).png new file mode 100644 index 00000000000..8861f880c08 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (27).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (28).png b/17/umbraco-cms/.gitbook/assets/image (28).png new file mode 100644 index 00000000000..da97b93df85 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (28).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (29).png b/17/umbraco-cms/.gitbook/assets/image (29).png new file mode 100644 index 00000000000..ede33c60a3f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (29).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (3).png b/17/umbraco-cms/.gitbook/assets/image (3).png new file mode 100644 index 00000000000..68d64b6ae00 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (3).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (30).png b/17/umbraco-cms/.gitbook/assets/image (30).png new file mode 100644 index 00000000000..ea822a4d4d4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (30).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (31).png b/17/umbraco-cms/.gitbook/assets/image (31).png new file mode 100644 index 00000000000..03716719629 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (31).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (32).png b/17/umbraco-cms/.gitbook/assets/image (32).png new file mode 100644 index 00000000000..03716719629 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (32).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (33).png b/17/umbraco-cms/.gitbook/assets/image (33).png new file mode 100644 index 00000000000..b9df7fb6648 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (33).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (4).png b/17/umbraco-cms/.gitbook/assets/image (4).png new file mode 100644 index 00000000000..67a9e94e1a6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (4).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (5).png b/17/umbraco-cms/.gitbook/assets/image (5).png new file mode 100644 index 00000000000..aa1a9a634cc Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (5).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (6).png b/17/umbraco-cms/.gitbook/assets/image (6).png new file mode 100644 index 00000000000..51f0f235ed6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (6).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (7).png b/17/umbraco-cms/.gitbook/assets/image (7).png new file mode 100644 index 00000000000..0ac6cdf8bc9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (7).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (8).png b/17/umbraco-cms/.gitbook/assets/image (8).png new file mode 100644 index 00000000000..eb4330ec76a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (8).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image (9).png b/17/umbraco-cms/.gitbook/assets/image (9).png new file mode 100644 index 00000000000..802e64acf80 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image (9).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image(001).png b/17/umbraco-cms/.gitbook/assets/image(001).png new file mode 100644 index 00000000000..013578fcea0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image(001).png differ diff --git a/17/umbraco-cms/.gitbook/assets/image.png b/17/umbraco-cms/.gitbook/assets/image.png new file mode 100644 index 00000000000..0b1c999d566 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/installed-package.png b/17/umbraco-cms/.gitbook/assets/installed-package.png new file mode 100644 index 00000000000..715cf1f9bcb Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/installed-package.png differ diff --git a/17/umbraco-cms/.gitbook/assets/launchJson.jpg b/17/umbraco-cms/.gitbook/assets/launchJson.jpg new file mode 100644 index 00000000000..a9a8171036e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/launchJson.jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/media-references-v9.png b/17/umbraco-cms/.gitbook/assets/media-references-v9.png new file mode 100644 index 00000000000..8cd405efa6b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/media-references-v9.png differ diff --git a/17/umbraco-cms/.gitbook/assets/member-image.png b/17/umbraco-cms/.gitbook/assets/member-image.png new file mode 100644 index 00000000000..7f90741a30b Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/member-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/menu-item.png b/17/umbraco-cms/.gitbook/assets/menu-item.png new file mode 100644 index 00000000000..f1f63f6aa15 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/menu-item.png differ diff --git a/17/umbraco-cms/.gitbook/assets/menu.png b/17/umbraco-cms/.gitbook/assets/menu.png new file mode 100644 index 00000000000..da3d9b2d237 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/menu.png differ diff --git a/17/umbraco-cms/.gitbook/assets/multilingual-site.png b/17/umbraco-cms/.gitbook/assets/multilingual-site.png new file mode 100644 index 00000000000..6a0121bf766 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/multilingual-site.png differ diff --git a/17/umbraco-cms/.gitbook/assets/multisite-image.png b/17/umbraco-cms/.gitbook/assets/multisite-image.png new file mode 100644 index 00000000000..78e415c519f Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/multisite-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1) (1).png b/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1) (1).png new file mode 100644 index 00000000000..728e7e9d1a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1) (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1).png b/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1).png new file mode 100644 index 00000000000..728e7e9d1a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/nothing-to-trim (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/nothing-to-trim.png b/17/umbraco-cms/.gitbook/assets/nothing-to-trim.png new file mode 100644 index 00000000000..728e7e9d1a0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/nothing-to-trim.png differ diff --git a/17/umbraco-cms/.gitbook/assets/notifications-image.png b/17/umbraco-cms/.gitbook/assets/notifications-image.png new file mode 100644 index 00000000000..136257d2190 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/notifications-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/package-properties.png b/17/umbraco-cms/.gitbook/assets/package-properties.png new file mode 100644 index 00000000000..b7fb1b0d7f5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/package-properties.png differ diff --git a/17/umbraco-cms/.gitbook/assets/packages-image (1).png b/17/umbraco-cms/.gitbook/assets/packages-image (1).png new file mode 100644 index 00000000000..796fe6fee73 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/packages-image (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/packages-image.png b/17/umbraco-cms/.gitbook/assets/packages-image.png new file mode 100644 index 00000000000..796fe6fee73 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/packages-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/pick-origin-root-node.png b/17/umbraco-cms/.gitbook/assets/pick-origin-root-node.png new file mode 100644 index 00000000000..611bc69c1ad Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/pick-origin-root-node.png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-config (1).png b/17/umbraco-cms/.gitbook/assets/property-editor-config (1).png new file mode 100644 index 00000000000..50af5d9de0c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-config (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-config-on (1).png b/17/umbraco-cms/.gitbook/assets/property-editor-config-on (1).png new file mode 100644 index 00000000000..ee2326d84ba Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-config-on (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-config-on.png b/17/umbraco-cms/.gitbook/assets/property-editor-config-on.png new file mode 100644 index 00000000000..ee2326d84ba Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-config-on.png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-config.png b/17/umbraco-cms/.gitbook/assets/property-editor-config.png new file mode 100644 index 00000000000..50af5d9de0c Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-config.png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-first-look.png b/17/umbraco-cms/.gitbook/assets/property-editor-first-look.png new file mode 100644 index 00000000000..f726712c340 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-first-look.png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-editor-first-spawn.png b/17/umbraco-cms/.gitbook/assets/property-editor-first-spawn.png new file mode 100644 index 00000000000..8ced358a695 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-editor-first-spawn.png differ diff --git a/17/umbraco-cms/.gitbook/assets/property-image.png b/17/umbraco-cms/.gitbook/assets/property-image.png new file mode 100644 index 00000000000..b36657bc7db Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/property-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/public-access-icon.png b/17/umbraco-cms/.gitbook/assets/public-access-icon.png new file mode 100644 index 00000000000..de45936b8ca Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/public-access-icon.png differ diff --git a/17/umbraco-cms/.gitbook/assets/requestcollection.png b/17/umbraco-cms/.gitbook/assets/requestcollection.png new file mode 100644 index 00000000000..8edad9f9d22 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/requestcollection.png differ diff --git a/17/umbraco-cms/.gitbook/assets/reversed-heart-hero.png b/17/umbraco-cms/.gitbook/assets/reversed-heart-hero.png new file mode 100644 index 00000000000..76011a1be13 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/reversed-heart-hero.png differ diff --git a/17/umbraco-cms/.gitbook/assets/rocket-hero.png b/17/umbraco-cms/.gitbook/assets/rocket-hero.png new file mode 100644 index 00000000000..8ec6e8bfcb8 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/rocket-hero.png differ diff --git a/17/umbraco-cms/.gitbook/assets/routing-image.png b/17/umbraco-cms/.gitbook/assets/routing-image.png new file mode 100644 index 00000000000..19eda19e188 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/routing-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/searching-image.png b/17/umbraco-cms/.gitbook/assets/searching-image.png new file mode 100644 index 00000000000..e5651e643a1 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/searching-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/section-empty.png b/17/umbraco-cms/.gitbook/assets/section-empty.png new file mode 100644 index 00000000000..62299525623 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/section-empty.png differ diff --git a/17/umbraco-cms/.gitbook/assets/section-menu-sidebar-app.svg b/17/umbraco-cms/.gitbook/assets/section-menu-sidebar-app.svg new file mode 100644 index 00000000000..393ab5ec2d8 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section-menu-sidebar-app.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/section-sidebar-apps.svg b/17/umbraco-cms/.gitbook/assets/section-sidebar-apps.svg new file mode 100644 index 00000000000..e781bc99002 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section-sidebar-apps.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/section-sidebar-composed-apps.svg b/17/umbraco-cms/.gitbook/assets/section-sidebar-composed-apps.svg new file mode 100644 index 00000000000..4081881518c --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section-sidebar-composed-apps.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/section-sidebar.svg b/17/umbraco-cms/.gitbook/assets/section-sidebar.svg new file mode 100644 index 00000000000..f88666f33e9 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section-sidebar.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/section-views.svg b/17/umbraco-cms/.gitbook/assets/section-views.svg new file mode 100644 index 00000000000..45c88317b91 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section-views.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/section.svg b/17/umbraco-cms/.gitbook/assets/section.svg new file mode 100644 index 00000000000..a525f169bf7 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/section.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/sections-assigning.png b/17/umbraco-cms/.gitbook/assets/sections-assigning.png new file mode 100644 index 00000000000..bad7898e2ac Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/sections-assigning.png differ diff --git a/17/umbraco-cms/.gitbook/assets/security-imag.png b/17/umbraco-cms/.gitbook/assets/security-imag.png new file mode 100644 index 00000000000..a47343805a9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/security-imag.png differ diff --git a/17/umbraco-cms/.gitbook/assets/selecting-an-icon.png b/17/umbraco-cms/.gitbook/assets/selecting-an-icon.png new file mode 100644 index 00000000000..37112c1d4d4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/selecting-an-icon.png differ diff --git a/17/umbraco-cms/.gitbook/assets/services-image.png b/17/umbraco-cms/.gitbook/assets/services-image.png new file mode 100644 index 00000000000..7a6268434f9 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/services-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/setup-image.png b/17/umbraco-cms/.gitbook/assets/setup-image.png new file mode 100644 index 00000000000..612f4b29011 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/setup-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/setup.png b/17/umbraco-cms/.gitbook/assets/setup.png new file mode 100644 index 00000000000..8b85307ba8e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/setup.png differ diff --git a/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome (1).webp b/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome (1).webp new file mode 100644 index 00000000000..8e14d6fe0e6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome (1).webp differ diff --git a/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome.webp b/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome.webp new file mode 100644 index 00000000000..8e14d6fe0e6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/spaces_G1Byxw7XfiZAj8zDMCTD_uploads_PtBQkEyVcGmoVx3ysAOJ_welcome.webp differ diff --git a/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor (1).webp b/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor (1).webp new file mode 100644 index 00000000000..a5af5f28cfa Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor (1).webp differ diff --git a/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor.webp b/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor.webp new file mode 100644 index 00000000000..a5af5f28cfa Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/spaces_OdQETpqkO0Kcv8KMquKL_uploads_git-blob-c7d7e59228a3b5738a1464489ef7601b7f8d350d_suggestion-property-editor.webp differ diff --git a/17/umbraco-cms/.gitbook/assets/specify-root-node.png b/17/umbraco-cms/.gitbook/assets/specify-root-node.png new file mode 100644 index 00000000000..6fa69a0a132 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/specify-root-node.png differ diff --git a/17/umbraco-cms/.gitbook/assets/starter-kit-image.png b/17/umbraco-cms/.gitbook/assets/starter-kit-image.png new file mode 100644 index 00000000000..150bd541804 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/starter-kit-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/static-templates.zip b/17/umbraco-cms/.gitbook/assets/static-templates.zip new file mode 100644 index 00000000000..5e0ee84185e Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/static-templates.zip differ diff --git a/17/umbraco-cms/.gitbook/assets/status.png b/17/umbraco-cms/.gitbook/assets/status.png new file mode 100644 index 00000000000..2109276c6b0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/status.png differ diff --git a/17/umbraco-cms/.gitbook/assets/suggestions-datatype.png b/17/umbraco-cms/.gitbook/assets/suggestions-datatype.png new file mode 100644 index 00000000000..89a27e7c12a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/suggestions-datatype.png differ diff --git a/17/umbraco-cms/.gitbook/assets/toolkit-image-4-3.png b/17/umbraco-cms/.gitbook/assets/toolkit-image-4-3.png new file mode 100644 index 00000000000..f1435b18627 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/toolkit-image-4-3.png differ diff --git a/17/umbraco-cms/.gitbook/assets/trees.image.png b/17/umbraco-cms/.gitbook/assets/trees.image.png new file mode 100644 index 00000000000..4579d6b0849 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/trees.image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/trim-confirm (1).png b/17/umbraco-cms/.gitbook/assets/trim-confirm (1).png new file mode 100644 index 00000000000..7c8a638ada0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/trim-confirm (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/trim-confirm.png b/17/umbraco-cms/.gitbook/assets/trim-confirm.png new file mode 100644 index 00000000000..7c8a638ada0 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/trim-confirm.png differ diff --git a/17/umbraco-cms/.gitbook/assets/uiLibraryCard (1).png b/17/umbraco-cms/.gitbook/assets/uiLibraryCard (1).png new file mode 100644 index 00000000000..21b2b6e4088 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/uiLibraryCard (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/uiLibraryCard.png b/17/umbraco-cms/.gitbook/assets/uiLibraryCard.png new file mode 100644 index 00000000000..21b2b6e4088 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/uiLibraryCard.png differ diff --git a/17/umbraco-cms/.gitbook/assets/uui-table-and-tag.png b/17/umbraco-cms/.gitbook/assets/uui-table-and-tag.png new file mode 100644 index 00000000000..950955fd251 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/uui-table-and-tag.png differ diff --git a/17/umbraco-cms/.gitbook/assets/uuiibox.png b/17/umbraco-cms/.gitbook/assets/uuiibox.png new file mode 100644 index 00000000000..f7c476f18ed Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/uuiibox.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-da (1).png b/17/umbraco-cms/.gitbook/assets/welcome-da (1).png new file mode 100644 index 00000000000..58bd8bda153 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-da (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-da.png b/17/umbraco-cms/.gitbook/assets/welcome-da.png new file mode 100644 index 00000000000..58bd8bda153 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-da.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-eng (1).png b/17/umbraco-cms/.gitbook/assets/welcome-eng (1).png new file mode 100644 index 00000000000..d1b3548aea5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-eng (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-eng.png b/17/umbraco-cms/.gitbook/assets/welcome-eng.png new file mode 100644 index 00000000000..d1b3548aea5 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-eng.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-hq.png b/17/umbraco-cms/.gitbook/assets/welcome-hq.png new file mode 100644 index 00000000000..728eb2f509a Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-hq.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-umb-user.png b/17/umbraco-cms/.gitbook/assets/welcome-umb-user.png new file mode 100644 index 00000000000..e57be41a2f2 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-umb-user.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcome-user-uuibox.png b/17/umbraco-cms/.gitbook/assets/welcome-user-uuibox.png new file mode 100644 index 00000000000..67197643bf4 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcome-user-uuibox.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomehpver.png b/17/umbraco-cms/.gitbook/assets/welcomehpver.png new file mode 100644 index 00000000000..b6508b176f6 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomehpver.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (1).png b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (1).png new file mode 100644 index 00000000000..d16deaf2b43 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (2).png b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (2).png new file mode 100644 index 00000000000..d16deaf2b43 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessage-v8.png b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8.png new file mode 100644 index 00000000000..d16deaf2b43 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessage-v8.png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (1).png b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (1).png new file mode 100644 index 00000000000..1664c32e550 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (1).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (2).png b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (2).png new file mode 100644 index 00000000000..1664c32e550 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10 (2).png differ diff --git a/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10.png b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10.png new file mode 100644 index 00000000000..1664c32e550 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/welcomemessagewithstyles-v10.png differ diff --git a/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (1).jpg b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (1).jpg new file mode 100644 index 00000000000..87e55037545 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (2).jpg b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (2).jpg new file mode 100644 index 00000000000..87e55037545 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (2).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (3).jpg b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (3).jpg new file mode 100644 index 00000000000..87e55037545 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1) (3).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1).jpg b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1).jpg new file mode 100644 index 00000000000..87e55037545 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/whatisadashboard-v10 (1).jpg differ diff --git a/17/umbraco-cms/.gitbook/assets/workspace-actions.svg b/17/umbraco-cms/.gitbook/assets/workspace-actions.svg new file mode 100644 index 00000000000..7ddeb6d9f35 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/workspace-actions.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/workspace-view-example.png b/17/umbraco-cms/.gitbook/assets/workspace-view-example.png new file mode 100644 index 00000000000..4190a1bc7d7 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/workspace-view-example.png differ diff --git a/17/umbraco-cms/.gitbook/assets/workspace-views.svg b/17/umbraco-cms/.gitbook/assets/workspace-views.svg new file mode 100644 index 00000000000..0c04fed189f --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/workspace-views.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/workspace.svg b/17/umbraco-cms/.gitbook/assets/workspace.svg new file mode 100644 index 00000000000..a897bd62814 --- /dev/null +++ b/17/umbraco-cms/.gitbook/assets/workspace.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/17/umbraco-cms/.gitbook/assets/zapier-image.png b/17/umbraco-cms/.gitbook/assets/zapier-image.png new file mode 100644 index 00000000000..0589efbfe34 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/zapier-image.png differ diff --git a/17/umbraco-cms/.gitbook/assets/zip-package-v9.png b/17/umbraco-cms/.gitbook/assets/zip-package-v9.png new file mode 100644 index 00000000000..169bbfb1591 Binary files /dev/null and b/17/umbraco-cms/.gitbook/assets/zip-package-v9.png differ diff --git a/17/umbraco-cms/.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md b/17/umbraco-cms/.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md new file mode 100644 index 00000000000..8c5aab07201 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md @@ -0,0 +1,7 @@ +--- +title: 'Obsolete Warning: IPublishedSnapshotAccessor' +--- + +{% hint style="warning" %} +The following example uses `IPublishedSnapshotAccessor`, which is obsolete in Umbraco 15 and will be removed in a future version. For more information, see the [Version specific upgrades](../../fundamentals/setup/upgrading/version-specific/#umbraco-15) article. +{% endhint %} diff --git a/17/umbraco-cms/.gitbook/includes/obsolete-warning-publishedsnapshot.md b/17/umbraco-cms/.gitbook/includes/obsolete-warning-publishedsnapshot.md new file mode 100644 index 00000000000..2597cee8417 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/obsolete-warning-publishedsnapshot.md @@ -0,0 +1,7 @@ +--- +title: 'Obsolete Warning: PublishedSnapshot' +--- + +{% hint style="warning" %} +The following example uses `PublishedSnapshot`, which is obsolete in Umbraco 15 and will be removed in a future version. For more information, see the [Version specific upgrades](../../fundamentals/setup/upgrading/version-specific/#umbraco-15) article. +{% endhint %} diff --git a/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot-publishedcache.md b/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot-publishedcache.md new file mode 100644 index 00000000000..92b5a44abca --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot-publishedcache.md @@ -0,0 +1,7 @@ +--- +title: 'Obsolete Warning: Snapshot and Published Cache' +--- + +{% hint style="warning" %} +The following example uses `Umbraco.Cms.Core.PublishedCache` and `IPublishedSnapshotAccessor` which are obsolete in Umbraco 15 and will be removed in a future version. For more information, see the [Version specific upgrades](../../fundamentals/setup/upgrading/version-specific/#umbraco-15) article. +{% endhint %} diff --git a/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot.md b/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot.md new file mode 100644 index 00000000000..0262b908421 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/obsolete-warning-snapshot.md @@ -0,0 +1,7 @@ +--- +title: 'Obsolete Warning: Snapshot' +--- + +{% hint style="warning" %} +The following example uses `Umbraco.Cms.Core.PublishedCache`, `IPublishedSnapshotAccessor`, and `PropertyCacheLevel.Snapshot`, which are obsolete in Umbraco 15 and will be removed in a future version. For more information, see the [Version specific upgrades](../../fundamentals/setup/upgrading/version-specific/#umbraco-15) article. +{% endhint %} diff --git a/17/umbraco-cms/.gitbook/includes/umbraco-extending-the-backoffice-training-course.md b/17/umbraco-cms/.gitbook/includes/umbraco-extending-the-backoffice-training-course.md new file mode 100644 index 00000000000..270412ffdb8 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/umbraco-extending-the-backoffice-training-course.md @@ -0,0 +1,7 @@ +--- +title: Umbraco Extending the Backoffice Training Course +--- + +Umbraco HQ offers a training course covering extending and customizing the Umbraco Backoffice to enhance the editing experience. The course targets frontend and backend developers familiar with Umbraco who want to extend the UI for editors. + +[Explore Extending the Backoffice Training Course](https://umbraco.com/training/course-details/extending-the-backoffice-details/) to learn more about the topics covered and how it can enhance your Umbraco development skills. diff --git a/17/umbraco-cms/.gitbook/includes/umbraco-fundamentals-training-course.md b/17/umbraco-cms/.gitbook/includes/umbraco-fundamentals-training-course.md new file mode 100644 index 00000000000..f5bab081116 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/umbraco-fundamentals-training-course.md @@ -0,0 +1,7 @@ +--- +title: Umbraco Fundamentals Training Course +--- + +Umbraco HQ offers a training course covering the basic concepts and features needed for building an Umbraco CMS website. The course targets frontend and backend developers, designers, and technical users who want to build a website from scratch in Umbraco, + +[Explore the Fundamentals Training Course](https://umbraco.com/training/course-details/fundamentals-details/) to learn more about the topics covered and how they can enhance your Umbraco development skills. diff --git a/17/umbraco-cms/.gitbook/includes/umbraco-load-balancing-training-course.md b/17/umbraco-cms/.gitbook/includes/umbraco-load-balancing-training-course.md new file mode 100644 index 00000000000..3b68d80560d --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/umbraco-load-balancing-training-course.md @@ -0,0 +1,7 @@ +--- +title: Umbraco Load Balancing Training Course +--- + +Umbraco HQ offers a training course covering the basics of working with Umbraco CMS in a load-balanced setup. The course targets backend developers and operations engineers. + +[Explore the Load Balancing Training Course](https://umbraco.com/training/course-details/load-balancing-and-azure/) to learn more about the topics covered and get more details about the course. diff --git a/17/umbraco-cms/.gitbook/includes/umbraco-mvc-training-course.md b/17/umbraco-cms/.gitbook/includes/umbraco-mvc-training-course.md new file mode 100644 index 00000000000..4c49e206302 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/umbraco-mvc-training-course.md @@ -0,0 +1,7 @@ +--- +title: Umbraco MVC Training Course +--- + +Umbraco HQ offers a training course covering everything you need to know about working with MVC in an Umbraco context. The course targets anyone who's interested in learning how to utilize Umbraco´s built-in features and basic functionality with standard MVC. + +[Explore the MVC course](https://umbraco.com/training/course-details/mvc-and-umbraco/) to learn more about the topics covered and how it can enhance your Umbraco development skills. diff --git a/17/umbraco-cms/.gitbook/includes/umbraco-searching-and-indexing-training-course.md b/17/umbraco-cms/.gitbook/includes/umbraco-searching-and-indexing-training-course.md new file mode 100644 index 00000000000..238eb1f60b3 --- /dev/null +++ b/17/umbraco-cms/.gitbook/includes/umbraco-searching-and-indexing-training-course.md @@ -0,0 +1,7 @@ +--- +title: Umbraco Searching and Indexing Training Course +--- + +Umbraco HQ offers a training course covering the inner workings of Examine and Lucene, query debugging, and knowledge of the search tool. The course targets backend ASP.NET MVC developers who need to build real-world search applications with Umbraco. + +[Explore the Searching and Indexing with Examine Training Course](https://umbraco.com/training/course-details/searching-and-indexing/) to learn more about the topics covered and how it can enhance your Umbraco development skills. diff --git a/17/umbraco-cms/README.md b/17/umbraco-cms/README.md new file mode 100644 index 00000000000..f33658787d0 --- /dev/null +++ b/17/umbraco-cms/README.md @@ -0,0 +1,35 @@ +--- +description: Your main resource when building and managing an Umbraco CMS website. +cover: .gitbook/assets/Umbraco 16 - Hero.jpg +coverY: 0 +--- + +# Umbraco CMS Documentation + +Umbraco CMS is a flexible and editor-friendly Content Management System (CMS) that allows you to create beautiful and modern websites. Use the latest version of .NET, integrate with your favorite services, and help your customers launch a website tailored to their specific needs. + +Learn more about Umbraco CMS and get an overview of the top features on [Umbraco.com](https://umbraco.com/products/umbraco-cms/). + +
FundamentalsLearn the basics of working with Umbraco CMS. How to install and setup your first site is also included in this section.Documentations Icons_Umbraco_CMS_Fundamentals.pngget-to-know-umbraco.md
Install Umbraco CMSReady to get started with Umbraco? Head over to the Setup section to learn how to install Umbraco CMS.Documentations Icons_Umbraco_CMS_Install.pnginstall
TutorialsFind detailed step-by-step guides on everything from building a site from scratch to implementing a custom maintenance page.Documentations Icons_Umbraco_CMS_Tutorials.pngoverview.md
+ +The documentation for Umbraco CMS provides information for experienced Umbraco and .NET developers. It also offers guides and high-level articles for people starting out with the CMS. + +{% content-ref url="tutorials/creating-a-basic-website/" %} +[creating-a-basic-website](tutorials/creating-a-basic-website/) +{% endcontent-ref %} + +{% content-ref url="reference/configuration/" %} +[configuration](reference/configuration/) +{% endcontent-ref %} + +{% content-ref url="fundamentals/setup/requirements.md" %} +[requirements.md](fundamentals/setup/requirements.md) +{% endcontent-ref %} + +{% content-ref url="reference/notifications/" %} +[notifications](reference/notifications/) +{% endcontent-ref %} + +*** + +{% include ".gitbook/includes/umbraco-fundamentals-training-course.md" %} diff --git a/17/umbraco-cms/SUMMARY.md b/17/umbraco-cms/SUMMARY.md new file mode 100644 index 00000000000..7cabd864b0c --- /dev/null +++ b/17/umbraco-cms/SUMMARY.md @@ -0,0 +1,520 @@ +# Table of contents + +* [Umbraco CMS Documentation](README.md) +* [Release Candidate Guide](release-candidate-guide.md) +* [Legacy Documentation](legacy-documentation/README.md) + * [Our Umbraco](https://our.umbraco.com/documentation/) + * [GitHub](https://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions) +* [Release Notes](https://our.umbraco.com/download/releases/) +* [Contribute](https://docs.umbraco.com/welcome/contribute/) +* [Sustainability Best Practices](https://docs.umbraco.com/sustainability-best-practices/) + +## Fundamentals + +* [Get to know Umbraco](fundamentals/get-to-know-umbraco.md) +* [Setup](fundamentals/setup/README.md) + * [Requirements](fundamentals/setup/requirements.md) + * [Installation](fundamentals/setup/install/README.md) + * [Install using .NET CLI](fundamentals/setup/install/install-umbraco-with-templates.md) + * [Running Umbraco in Docker using Docker Compose](fundamentals/setup/install/running-umbraco-on-docker-locally.md) + * [Install using Visual Studio](fundamentals/setup/install/visual-studio.md) + * [Local IIS With Umbraco](fundamentals/setup/install/iis.md) + * [Install using Visual Studio Code](fundamentals/setup/install/install-umbraco-with-vs-code.md) + * [Installing Nightly Builds](fundamentals/setup/install/installing-nightly-builds.md) + * [Running Umbraco on Linux/macOS](fundamentals/setup/install/running-umbraco-on-linux-macos.md) + * [Unattended Installs](fundamentals/setup/install/unattended-install.md) + * [Upgrade your project](fundamentals/setup/upgrading/README.md) + * [Upgrades in Umbraco](fundamentals/setup/upgrading/upgrade-introduction.md) + * [Upgrade Details](fundamentals/setup/upgrading/upgrade-details.md) + * [Version Specific Upgrades](fundamentals/setup/upgrading/version-specific/README.md) + * [Upgrade from Umbraco 8 to the latest version](fundamentals/setup/upgrading/version-specific/upgrade-from-8-to-latest.md) + * [Migrate content to Umbraco 15](fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-15.md) + * [Migrate content to Umbraco 8](fundamentals/setup/upgrading/version-specific/migrate-content-to-umbraco-8.md) + * [Minor upgrades for Umbraco 8](fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-8.md) + * [Upgrade to Umbraco 7](fundamentals/setup/upgrading/version-specific/upgrade-to-umbraco-7.md) + * [Minor upgrades for Umbraco 7](fundamentals/setup/upgrading/version-specific/minor-upgrades-for-umbraco-7.md) + * [Upgrade Unattended](fundamentals/setup/upgrading/upgrade-unattended.md) + * [Downgrades and Re-running Migrations](fundamentals/setup/upgrading/downgrades-and-rerunning-migrations.md) + * [Server setup](fundamentals/setup/server-setup/README.md) + * [Running Umbraco On Azure Web Apps](fundamentals/setup/server-setup/azure-web-apps.md) + * [Hosting Umbraco in IIS](fundamentals/setup/server-setup/iis.md) + * [File And Folder Permissions](fundamentals/setup/server-setup/permissions.md) + * [Runtime Modes](fundamentals/setup/server-setup/runtime-modes.md) + * [Running Umbraco in Docker](fundamentals/setup/server-setup/running-umbraco-in-docker.md) + * [Umbraco in Load Balanced Environments](fundamentals/setup/server-setup/load-balancing/README.md) + * [Load Balancing Azure Web Apps](fundamentals/setup/server-setup/load-balancing/azure-web-apps.md) + * [Standalone File System](fundamentals/setup/server-setup/load-balancing/file-system-replication.md) + * [Advanced Techniques With Flexible Load Balancing](fundamentals/setup/server-setup/load-balancing/flexible-advanced.md) + * [Logging With Load Balancing](fundamentals/setup/server-setup/load-balancing/logging.md) +* [Backoffice](fundamentals/backoffice/README.md) + * [Sections](fundamentals/backoffice/sections.md) + * [Property Editors](fundamentals/backoffice/property-editors/README.md) + * [Built-in Property Editors](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md) + * [Checkbox List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md) + * [Collection](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md) + * [Color Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md) + * [Content Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md) + * [Document Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/document-picker.md) + * [DateTime](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md) + * [Date](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md) + * [Decimal](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md) + * [Email Address](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md) + * [Eye Dropper Color Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md) + * [File Upload](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md) + * [Image Cropper](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md) + * [Label](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md) + * [Markdown Editor](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md) + * [Media Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md) + * [Member Group Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md) + * [Member Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md) + * [Multi Url Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md) + * [Repeatable Textstrings](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md) + * [Numeric](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md) + * [Radiobutton List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md) + * [Slider](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/slider.md) + * [Tags](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/tags.md) + * [Textarea](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textarea.md) + * [Textbox](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textbox.md) + * [Toggle](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/true-false.md) + * [User Picker](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/user-picker.md) + * [Block Editors](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md) + * [Block Grid](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md) + * [Block List](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md) + * [Block Level Variance](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-level-variance.md) + * [Dropdown](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md) + * [Rich Text Editor](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md) + * [Configuration](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md) + * [Blocks](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md) + * [Custom CSS properties](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/css-properties.md) + * [Extensions](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md) + * [Style Menu](fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/style-menu.md) + * [Login](fundamentals/backoffice/login.md) + * [Document Blueprints](fundamentals/backoffice/document-blueprints.md) + * [Sidebar](fundamentals/backoffice/sidebar.md) + * [Log Viewer](fundamentals/backoffice/logviewer.md) + * [Language Variants](fundamentals/backoffice/variants.md) + * [Settings Dashboards](fundamentals/backoffice/settings-dashboards.md) +* [Data](fundamentals/data/README.md) + * [Defining Content](fundamentals/data/defining-content/README.md) + * [Default Document Types](fundamentals/data/defining-content/default-document-types.md) + * [Document Type Localization](fundamentals/data/defining-content/document-type-localization.md) + * [Creating Media](fundamentals/data/creating-media/README.md) + * [Default Data/Media Types](fundamentals/data/creating-media/default-media-types.md) + * [Members](fundamentals/data/members.md) + * [Data Types](fundamentals/data/data-types/README.md) + * [Default Data Types](fundamentals/data/data-types/default-data-types.md) + * [Scheduled Publishing](fundamentals/data/scheduled-publishing.md) + * [Using Tabs](fundamentals/data/adding-tabs.md) + * [Users](fundamentals/data/users/README.md) + * [API Users](fundamentals/data/users/api-users.md) + * [Relations](fundamentals/data/relations.md) + * [Dictionary Items](fundamentals/data/dictionary-items.md) + * [Content Version Cleanup](fundamentals/data/content-version-cleanup.md) +* [Design](fundamentals/design/README.md) + * [Templates](fundamentals/design/templates/README.md) + * [Basic Razor Syntax](fundamentals/design/templates/basic-razor-syntax.md) + * [Razor Cheatsheet](fundamentals/design/templates/razor-cheatsheet.md) + * [Rendering Content](fundamentals/design/rendering-content.md) + * [Rendering Media](fundamentals/design/rendering-media.md) + * [Partial Views](fundamentals/design/partial-views.md) + * [Stylesheets And JavaScript](fundamentals/design/stylesheets-javascript.md) +* [Code](fundamentals/code/README.md) + * [Service APIs](fundamentals/code/umbraco-services.md) + * [Subscribing To Notifications](fundamentals/code/subscribing-to-notifications.md) + * [Creating Forms](fundamentals/code/creating-forms.md) + * [Debugging](fundamentals/code/debugging/README.md) + * [Logging](fundamentals/code/debugging/logging.md) + * [Source Control](fundamentals/code/source-control.md) + +## Implementation + +* [Learn how Umbraco works](implementation/learn-how-umbraco-works.md) +* [Routing](implementation/default-routing/README.md) + * [Controller & Action Selection](implementation/default-routing/controller-selection.md) + * [Execute Request](implementation/default-routing/execute-request.md) + * [Request Pipeline](implementation/default-routing/inbound-pipeline.md) +* [Custom Routing](implementation/custom-routing/README.md) + * [Adding a hub with SignalR and Umbraco](implementation/custom-routing/signalR.md) +* [Controllers](implementation/controllers.md) +* [Data Persistence (CRUD)](implementation/data-persistence.md) +* [Composing](implementation/composing.md) +* [Integration Testing](implementation/integration-testing.md) +* [Nullable Reference Types](implementation/nullable-reference-types.md) +* [Services and Helpers](implementation/services/README.md) + * [Circular Dependencies](implementation/services/circular-dependencies.md) +* [Unit Testing](implementation/unit-testing.md) + +## Customizing Backoffice + +* [Overview](customizing/overview.md) +* [Setup Your Development Environment](customizing/development-flow/README.md) + * [Umbraco Extension Template](customizing/development-flow/umbraco-extension-template.md) + * [Vite Package Setup](customizing/development-flow/vite-package-setup.md) +* [Extensions Overview](customizing/extending-overview/README.md) + * [Extension Registry](customizing/extending-overview/extension-registry/README.md) + * [Register an Extension](customizing/extending-overview/extension-registry/extension-registry.md) + * [Extension Manifest](customizing/extending-overview/extension-registry/extension-manifest.md) + * [Replace, Exclude or Unregister](customizing/extending-overview/extension-registry/replace-exclude-or-unregister.md) + * [Extension Types](customizing/extending-overview/extension-types/README.md) + * [App Entry Point](customizing/extending-overview/extension-types/app-entry-point.md) + * [Backoffice Entry Point](customizing/extending-overview/extension-types/backoffice-entry-point.md) + * [Block Custom View](customizing/extending-overview/extension-types/block-custom-view.md) + * [Bundle](customizing/extending-overview/extension-types/bundle.md) + * [Dashboards](customizing/extending-overview/extension-types/dashboard.md) + * [Entity Actions](customizing/extending-overview/extension-types/entity-actions.md) + * [Entity Bulk Actions](customizing/extending-overview/extension-types/entity-bulk-actions.md) + * [Entity Create Option Action](customizing/extending-overview/extension-types/entity-create-option-action.md) + * [Extension Conditions](customizing/extending-overview/extension-types/condition.md) + * [Global Context](customizing/extending-overview/extension-types/global-context.md) + * [Header Apps](customizing/extending-overview/extension-types/header-apps.md) + * [Icons](customizing/extending-overview/extension-types/icons.md) + * [Kinds](customizing/extending-overview/extension-types/kind.md) + * [Localization](customizing/extending-overview/extension-types/localization.md) + * [Menu](customizing/extending-overview/extension-types/menu.md) + * [Modals](customizing/extending-overview/extension-types/modals/README.md) + * [Confirm Dialog](customizing/extending-overview/extension-types/modals/confirm-dialog.md) + * [Custom Modals](customizing/extending-overview/extension-types/modals/custom-modals.md) + * [Modal Route Registration](customizing/extending-overview/extension-types/modals/route-registration.md) + * [Property Value Preset](customizing/extending-overview/extension-types/property-value-preset.md) + * [Sections](customizing/extending-overview/extension-types/sections/README.md) + * [Section](customizing/extending-overview/extension-types/sections/section.md) + * [Section Sidebar](customizing/extending-overview/extension-types/sections/section-sidebar.md) + * [Section View](customizing/extending-overview/extension-types/sections/section-view.md) + * [Trees](customizing/extending-overview/extension-types/tree.md) + * [Workspaces](customizing/extending-overview/extension-types/workspaces/README.md) + * [Workspace Actions](customizing/extending-overview/extension-types/workspaces/workspace-editor-actions.md) + * [Workspace Context](customizing/extending-overview/extension-types/workspaces/workspace-context.md) + * [Workspace Views](customizing/extending-overview/extension-types/workspaces/workspace-views.md) + * [Extension Kind](customizing/extending-overview/extension-kind.md) + * [Extension Conditions](customizing/extending-overview/extension-conditions.md) + * [Custom Extension types](customizing/extending-overview/custom-extension-type.md) +* [Foundation](customizing/foundation/README.md) + * [Fetching Data](customizing/foundation/fetching-data/README.md) + * [Fetch API](customizing/foundation/fetching-data/fetch-api.md) + * [Umbraco HTTP Client](customizing/foundation/fetching-data/http-client.md) + * [Executing Requests](customizing/foundation/fetching-data/try-execute.md) + * [Custom Generated Client](customizing/foundation/fetching-data/custom-generated-client.md) + * [Terminology](customizing/foundation/terminology.md) + * [Umbraco Controller](customizing/foundation/umbraco-controller/README.md) + * [Write your own controller](customizing/foundation/umbraco-element/controllers/write-your-own-controller.md) + * [Umbraco Element](customizing/foundation/umbraco-element/README.md) + * [Lit Element](customizing/foundation/lit-element.md) + * [Context API](customizing/foundation/context-api/README.md) + * [Consume a Context](customizing/foundation/context-api/consume-a-context.md) + * [Provide a Context](customizing/foundation/context-api/provide-a-context.md) + * [Repositories](customizing/foundation/repositories.md) + * [States](customizing/foundation/states.md) + * [UI Sorting](customizing/foundation/sorting.md) + * [Routes](customizing/foundation/routes.md) + * [Backoffice Localization](customizing/foundation/localization.md) + * [Integrate Validation](customizing/foundation/integrate-validation.md) +* [Contexts](customizing/foundation/contexts/README.md) + * [Property Dataset Context](customizing/foundation/contexts/property-dataset-context.md) +* [Sections & Trees](customizing/section-trees.md) +* [Property Level UI Permissions](customizing/property-level-ui-permissions.md) +* [Icons](customizing/foundation/icons.md) +* [Searchable Trees (ISearchableTree)](customizing/searchable-trees.md) +* [Property Editors](customizing/property-editors/README.md) + * [Property Editor Validation](customizing/property-editors/property-editor-validation.md) + * [Property Editors Composition](customizing/property-editors/composition/README.md) + * [Property Editor Schema](customizing/property-editors/composition/property-editor-schema.md) + * [Property Editor UI](customizing/property-editors/composition/property-editor-ui.md) + * [Property Value Converters](customizing/property-editors/property-value-converters.md) + * [Property Value Converter Example](customizing/property-editors/full-examples-value-converters.md) + * [Property Actions](customizing/property-editors/property-actions.md) + * [Integrate Property Editors](customizing/property-editors/integrate-property-editors.md) + * [Tracking References](customizing/property-editors/tracking.md) + * [Property Dataset](customizing/property-editors/property-dataset.md) +* [Workspaces](customizing/workspaces.md) +* [Umbraco Package](customizing/umbraco-package.md) +* [UI Library](customizing/ui-library.md) +* [Examples and Playground](examples-and-playground.md) + +## Extending Umbraco + +* [Overview](extending/build-on-umbraco-functionality.md) +* [Health Check](extending/health-check/README.md) + * [Health Check Guides](extending/health-check/guides/README.md) + * [Click-Jacking Protection](extending/health-check/guides/clickjackingprotection.md) + * [Content Content Security Policy (CSP)](extending/health-check/guides/contentsecuritypolicy.md) + * [Content/MIME Sniffing Protection](extending/health-check/guides/contentsniffingprotection.md) + * [Cross-site scripting Protection (X-XSS-Protection header)](extending/health-check/guides/crosssitescriptingprotection.md) + * [Debug Compilation Mode](extending/health-check/guides/debugcompilationmode.md) + * [Excessive Headers](extending/health-check/guides/excessiveheaders.md) + * [Fixed Application Url](extending/health-check/guides/fixedapplicationurl.md) + * [Folder & File Permissions](extending/health-check/guides/folderandfilepermissions.md) + * [HTTPS Configuration](extending/health-check/guides/httpsconfiguration.md) + * [Notification Email Settings](extending/health-check/guides/notificationemail.md) + * [SMTP](extending/health-check/guides/smtp.md) + * [Strict-Transport-Security Header](extending/health-check/guides/stricttransportsecurityheader.md) +* [Language Files & Localization](extending/language-files/README.md) + * [.NET Localization](extending/language-files/net-localization.md) +* [Backoffice Search](extending/backoffice-search.md) +* [Creating a Custom Database Table](extending/database.md) +* [Creating a Custom Seed Key Provider](extending/creating-custom-seed-key-provider.md) +* [Embedded Media Providers](extending/embedded-media-providers.md) +* [Custom File Systems (IFileSystem)](extending/filesystemproviders/README.md) + * [Using Azure Blob Storage for Media and ImageSharp Cache](extending/filesystemproviders/azure-blob-storage.md) +* [Configuring Azure Key Vault](extending/key-vault.md) +* [Server Events From SignalR](extending/server-events.md) +* [Packages](extending/packages/README.md) + * [Creating a Package](extending/packages/creating-a-package.md) + * [Language file for packages](extending/packages/language-files-for-packages.md) + * [Listing a Package on the Umbraco Marketplace](extending/packages/listing-on-marketplace.md) + * [Good practice and defaults](extending/packages/good-practice-and-defaults.md) + * [Packages on Umbraco Cloud](extending/packages/packages-on-umbraco-cloud.md) + * [Installing and Uninstalling Packages](extending/packages/installing-and-uninstalling-packages.md) + * [Maintaining packages](extending/packages/maintaining-packages.md) + * [Create accessible Umbraco packages](extending/packages/accessibility.md) + * [Example Package Repository](extending/packages/example-package-repository.md) + +## Reference + +* [Dive into the code](reference/dive-into-the-code.md) +* [Configuration](reference/configuration/README.md) + * [Basic Authentication Settings](reference/configuration/basicauthsettings.md) + * [Connection strings settings](reference/configuration/connectionstringssettings.md) + * [Content Dashboard Settings](reference/configuration/contentdashboard.md) + * [Content Settings](reference/configuration/contentsettings.md) + * [Data Types Settings](reference/configuration/datatypes.md) + * [Debug settings](reference/configuration/debugsettings.md) + * [Examine settings](reference/configuration/examinesettings.md) + * [Exception filter settings](reference/configuration/exceptionfiltersettings.md) + * [FileSystemProviders Configuration](reference/configuration/filesystemproviders.md) + * [Global Settings](reference/configuration/globalsettings.md) + * [Health checks](reference/configuration/healthchecks.md) + * [Hosting settings](reference/configuration/hostingsettings.md) + * [Imaging settings](reference/configuration/imagingsettings.md) + * [Indexing settings](reference/configuration/indexingsettings.md) + * [Install Default Data Settings](reference/configuration/installdefaultdatasettings.md) + * [Logging settings](reference/configuration/loggingsettings.md) + * [Maximum Upload Size Settings](reference/configuration/maximumuploadsizesettings.md) + * [Models builder settings](reference/configuration/modelsbuildersettings.md) + * [Cache Settings](reference/configuration/cache-settings.md) + * [Package Migration](reference/configuration/packagemigrationsettings.md) + * [Plugins settings](reference/configuration/pluginssettings.md) + * [Request handler settings](reference/configuration/requesthandlersettings.md) + * [Runtime settings](reference/configuration/runtimesettings.md) + * [Security Settings](reference/configuration/securitysettings.md) + * [Serilog settings](reference/configuration/serilog.md) + * [Type finder settings](reference/configuration/typefindersettings.md) + * [Unattended](reference/configuration/unattendedsettings.md) + * [Web routing](reference/configuration/webroutingsettings.md) +* [Templating](reference/templating/README.md) + * [Models Builder](reference/templating/modelsbuilder/README.md) + * [Introduction](reference/templating/modelsbuilder/introduction.md) + * [Configuration](reference/templating/modelsbuilder/configuration.md) + * [Builder Modes](reference/templating/modelsbuilder/builder-modes.md) + * [Understand and Extend](reference/templating/modelsbuilder/understand-and-extend.md) + * [Using Interfaces](reference/templating/modelsbuilder/using-interfaces.md) + * [Tips and Tricks](reference/templating/modelsbuilder/coolthingswithmodels.md) + * [Working with MVC](reference/templating/mvc/README.md) + * [Working with MVC Views in Umbraco](reference/templating/mvc/views.md) + * [View/Razor Examples](reference/templating/mvc/examples.md) + * [Using MVC Partial Views in Umbraco](reference/templating/mvc/partial-views.md) + * [Using View Components in Umbraco](reference/templating/mvc/viewcomponents.md) + * [Querying & Traversal](reference/templating/mvc/querying.md) + * [Creating Forms](reference/templating/mvc/forms.md) + * [Macros](reference/templating/macros.md) +* [Querying & Models](reference/querying/README.md) + * [IMemberManager](reference/querying/imembermanager.md) + * [IPublishedContentQuery](reference/querying/ipublishedcontentquery.md) + * [ITagQuery](reference/querying/itagquery.md) + * [UDI Identifiers](reference/querying/udi-identifiers.md) + * [UmbracoContext helper](reference/querying/umbraco-context.md) + * [UmbracoHelper](reference/querying/umbracohelper.md) + * [IPublishedContent](reference/querying/ipublishedcontent/README.md) + * [IPublishedContent Collections](reference/querying/ipublishedcontent/collections.md) + * [IPublishedContent IsHelpers](reference/querying/ipublishedcontent/ishelpers.md) + * [IPublishedContent Property Access & Extension Methods](reference/querying/ipublishedcontent/properties.md) +* [Routing & Controllers](reference/routing/README.md) + * [Custom MVC controllers (Umbraco Route Hijacking)](reference/routing/custom-controllers.md) + * [Custom MVC Routes](reference/routing/custom-routes.md) + * [Custom Middleware](reference/routing/custom-middleware.md) + * [URL Rewrites in Umbraco](reference/routing/iisrewriterules.md) + * [Special Property Type aliases for routing](reference/routing/routing-properties.md) + * [URL Redirect Management](reference/routing/url-tracking.md) + * [Routing in Umbraco](reference/routing/request-pipeline/README.md) + * [FindPublishedContentAndTemplate()](reference/routing/request-pipeline/find-publishedcontent-and-template.md) + * [IContentFinder](reference/routing/request-pipeline/icontentfinder.md) + * [Inbound request pipeline](reference/routing/request-pipeline/inbound-pipeline.md) + * [Outbound request pipeline](reference/routing/request-pipeline/outbound-pipeline.md) + * [Published Content Request Preparation](reference/routing/request-pipeline/published-content-request-preparation.md) + * [Surface controllers](reference/routing/surface-controllers/README.md) + * [Surface controller actions](reference/routing/surface-controllers/surface-controllers-actions.md) + * [Umbraco API Controllers](reference/routing/umbraco-api-controllers/README.md) + * [Porting old Umbraco API Controllers](reference/routing/umbraco-api-controllers/porting-old-umbraco-apis.md) +* [Content Delivery API](reference/content-delivery-api/README.md) + * [Custom property editors support](reference/content-delivery-api/custom-property-editors-support.md) + * [Extension API for querying](reference/content-delivery-api/extension-api-for-querying.md) + * [Media Delivery API](reference/content-delivery-api/media-delivery-api.md) + * [Protected content in the Delivery API](reference/content-delivery-api/protected-content-in-the-delivery-api/README.md) + * [Server to server access](reference/content-delivery-api/protected-content-in-the-delivery-api/server-to-server-access.md) + * [Output caching](reference/content-delivery-api/output-caching.md) + * [Property expansion and limiting](reference/content-delivery-api/property-expansion-and-limiting.md) + * [Additional preview environments support](reference/content-delivery-api/additional-preview-environments-support.md) +* [Webhooks](reference/webhooks/README.md) + * [Expanding Webhook Events](reference/webhooks/expanding-webhook-events.md) +* [API versioning and OpenAPI](reference/api-versioning-and-openapi.md) +* [Searching](reference/searching/README.md) + * [Examine](reference/searching/examine/README.md) + * [Examine Management](reference/searching/examine/examine-management.md) + * [Examine Manager](reference/searching/examine/examine-manager.md) + * [Custom indexing](reference/searching/examine/indexing.md) + * [PDF indexes and multisearchers](reference/searching/examine/pdfindex-multisearcher.md) + * [Quick-start](reference/searching/examine/quick-start.md) + * [Corrupt Indexes](reference/searching/examine/corrupt-indexes.md) +* [Using Notifications](reference/notifications/README.md) + * [Notification Handler](reference/notifications/notification-handler.md) + * [CacheRefresher Notifications Example](reference/notifications/cacherefresher-notifications.md) + * [ContentService Notifications Example](reference/notifications/contentservice-notifications.md) + * [Creating And Publishing Notifications](reference/notifications/creating-and-publishing-notifications.md) + * [Determining if an entity is new](reference/notifications/determining-new-entity.md) + * [MediaService Notifications Example](reference/notifications/mediaservice-notifications.md) + * [MemberService Notifications Example](reference/notifications/memberservice-notifications.md) + * [Umbraco Application Lifetime Notifications](reference/notifications/umbracoapplicationlifetime-notifications.md) + * [EditorModel Notifications](reference/notifications/editormodel-notifications/README.md) + * [Hot vs. cold restarts](reference/notifications/hot-vs-cold-restarts.md) +* [Inversion of Control / Dependency injection](reference/using-ioc.md) +* [Management](reference/management/README.md) + * [Using Umbraco services](reference/management/using-services/README.md) + * [Consent Service](reference/management/using-services/consentservice.md) + * [Media Service](reference/management/using-services/mediaservice.md) + * [Relation Service](reference/management/using-services/relationservice.md) + * [Content Service](reference/management/using-services/contentservice.md) + * [Content Type Service](reference/management/using-services/contenttypeservice.md) + * [Localization Service](reference/management/using-services/localizationservice.md) + * [User Service](reference/management/using-services/userservice.md) +* [Plugins](reference/plugins/README.md) + * [Creating Resolvers](reference/plugins/creating-resolvers.md) + * [Finding types](reference/plugins/finding-types.md) +* [Cache & Distributed Cache](reference/cache/README.md) + * [Cache Seeding](reference/cache/cache-seeding.md) + * [Accessing the cache](reference/cache/application-cache.md) + * [ICacheRefresher](reference/cache/icacherefresher.md) + * [IMemberPartialViewCacheInvalidator](reference/cache/imemberpartialviewcacheinvalidator.md) + * [IServerMessenger](reference/cache/iservermessenger.md) + * [Getting/Adding/Updating/Inserting Into Cache](reference/cache/updating-cache.md) + * [Examples](reference/cache/examples/README.md) + * [Working with caching](reference/cache/examples/tags.md) +* [Response Caching](reference/response-caching.md) +* [Security](reference/security/README.md) + * [API rate limiting](reference/security/api-rate-limiting.md) + * [BackOfficeUserManager and Events](reference/security/backofficeusermanager-and-notifications.md) + * [Cookies](reference/security/cookies.md) + * [Replacing the basic username/password check](reference/security/custom-password-check.md) + * [External login providers](reference/security/external-login-providers.md) + * [Locking of Users and password reset](reference/security/password-reset.md) + * [Reset admin password](reference/security/reset-admin-password.md) + * [Umbraco Security Hardening](reference/security/security-hardening.md) + * [Umbraco Security Settings](reference/security/security-settings.md) + * [Sensitive data](reference/security/sensitive-data-on-members.md) + * [Sanitizing the Rich Text Editor](reference/security/serverside-sanitizing.md) + * [Setup Umbraco for a FIPS Compliant Server](reference/security/setup-umbraco-for-a-fips-server.md) + * [HTTPS](reference/security/ssl-https.md) + * [Two-factor Authentication](reference/security/two-factor-authentication.md) + * [Server-side file validation](reference/security/serverside-file-validation.md) +* [Scheduling](reference/scheduling.md) +* [Common Pitfalls & Anti-Patterns](reference/common-pitfalls.md) +* [API Documentation](reference/api-documentation.md) +* [Debugging with SourceLink](reference/debugging.md) +* [Language Variation](reference/language-variation.md) +* [UmbracoMapper](reference/mapping.md) +* [Distributed Locks](reference/distributed-locks.md) +* [Management API](reference/management-api/README.md) + * [External Access](reference/management-api/external-access.md) + * [Setup OAuth using Postman](reference/management-api/postman-setup-swagger.md) +* [Custom Swagger API](reference/custom-swagger-api.md) +* [Umbraco Flavored Markdown](reference/umbraco-flavored-markdown.md) +* [Content Type Filters](reference/content-type-filters.md) +* [Database Availability Checks](reference/database-availability.md) +* [JSON Serialization](reference/json-serialization.md) +* [Property Editor UIs](reference/property-editor-uis/README.md) + +## Tutorials + +* [Overview](tutorials/overview.md) +* [Creating a Basic Website](tutorials/creating-a-basic-website/README.md) + * [Getting Started](tutorials/creating-a-basic-website/getting-started.md) + * [Document Types](tutorials/creating-a-basic-website/document-types.md) + * [Creating Your First Template](tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md) + * [CSS and Images](tutorials/creating-a-basic-website/css-and-images.md) + * [Displaying the Document Type Properties](tutorials/creating-a-basic-website/displaying-the-document-type-properties.md) + * [Creating a Master Template](tutorials/creating-a-basic-website/creating-master-template-part-1.md) + * [Creating Pages and Using the Master Template](tutorials/creating-a-basic-website/creating-master-template-part-2.md) + * [Setting the Navigation Menu](tutorials/creating-a-basic-website/setting-the-navigation-menu.md) + * [Articles and Article Items](tutorials/creating-a-basic-website/article-parent-and-article-items.md) + * [Adding Language Variants](tutorials/creating-a-basic-website/adding-language-variants.md) + * [Conclusions](tutorials/creating-a-basic-website/conclusion.md) +* [Creating your First Extension](tutorials/creating-your-first-extension.md) +* [Creating a Custom Dashboard](tutorials/creating-a-custom-dashboard/README.md) + * [Adding localization to the dashboard](tutorials/creating-a-custom-dashboard/adding-localization-to-the-dashboard.md) + * [Adding functionality to the Dashboard](tutorials/creating-a-custom-dashboard/adding-functionality-to-the-dashboard.md) + * [Using Umbraco UI library in the Dashboard](tutorials/creating-a-custom-dashboard/extending-the-dashboard-using-umbraco-ui-library.md) +* [Creating a Property Editor](tutorials/creating-a-property-editor/README.md) + * [Adding configuration to a Property Editor](tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md) + * [Integrating context with a Property Editor](tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md) + * [Custom value conversion for rendering](tutorials/creating-a-property-editor/custom-value-conversion-for-rendering.md) + * [Adding server-side validation](tutorials/creating-a-property-editor/adding-server-side-validation.md) + * [Default Property Editor Schema aliases](tutorials/creating-a-property-editor/default-property-editor-schema-aliases.md) +* [Creating a Multilingual Site](tutorials/multilanguage-setup.md) +* [Add Google Authentication (Users)](tutorials/add-google-authentication.md) +* [Add Microsoft Entra ID authentication (Members)](tutorials/add-microsoft-entra-id-authentication.md) +* [Creating Custom Database Tables with Entity Framework](tutorials/getting-started-with-entity-framework-core.md) +* [Migrating Macros](tutorials/migrating-macros.md) +* [The Starter Kit](tutorials/starter-kit/README.md) + * [Install the Starter Kit](tutorials/starter-kit/install-the-starter-kit.md) + * [Lessons](tutorials/starter-kit/lessons/README.md) + * [Customize the Starter Kit](tutorials/starter-kit/lessons/1-customize-the-starter-kit.md) + * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/README.md) + * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/part-2.md) + * [Add a Blog Post Publication Date](tutorials/starter-kit/lessons/2-add-a-blog-post-publication-date/part-3.md) + * [Add Open Graph](tutorials/starter-kit/lessons/3-add-open-graph/README.md) + * [Add Open Graph - Step 1](tutorials/starter-kit/lessons/3-add-open-graph/step-1.md) + * [Add Open Graph - Step 2](tutorials/starter-kit/lessons/3-add-open-graph/step-2.md) + * [Add Open Graph - Step 3](tutorials/starter-kit/lessons/3-add-open-graph/step-3.md) + * [Add Open Graph - Step 4](tutorials/starter-kit/lessons/3-add-open-graph/step-4.md) + * [Add Open Graph - Summary](tutorials/starter-kit/lessons/3-add-open-graph/summary.md) + * [Ask For Help and Join the Community](tutorials/starter-kit/lessons/4-help-and-community.md) +* [Editor's Manual](tutorials/editors-manual/README.md) + * [Getting Started](tutorials/editors-manual/getting-started-with-umbraco/README.md) + * [Logging In and Out](tutorials/editors-manual/getting-started-with-umbraco/logging-in-and-out.md) + * [Umbraco Interface](tutorials/editors-manual/getting-started-with-umbraco/umbraco-interface.md) + * [Creating, Saving and Publishing Content Options](tutorials/editors-manual/getting-started-with-umbraco/creating-saving-and-publishing-content.md) + * [Finding Content](tutorials/editors-manual/getting-started-with-umbraco/finding-content.md) + * [Editing Existing Content](tutorials/editors-manual/getting-started-with-umbraco/editing-existing-content.md) + * [Sorting Pages](tutorials/editors-manual/getting-started-with-umbraco/ordering-pages.md) + * [Moving a Page](tutorials/editors-manual/getting-started-with-umbraco/moving-a-page.md) + * [Copying a Page](tutorials/editors-manual/getting-started-with-umbraco/copying-a-page.md) + * [Deleting and Restoring Pages](tutorials/editors-manual/getting-started-with-umbraco/deleting-and-restoring-pages.md) + * [Working with Rich Text Editor](tutorials/editors-manual/working-with-content/README.md) + * [Version Management](tutorials/editors-manual/version-management/README.md) + * [Comparing Versions](tutorials/editors-manual/version-management/comparing-versions.md) + * [Rollback to a Previous Version](tutorials/editors-manual/version-management/rollback-to-a-previous-version.md) + * [Media Management](tutorials/editors-manual/media-management/README.md) + * [Working with Folders](tutorials/editors-manual/media-management/working-with-folders.md) + * [Working with Media Types](tutorials/editors-manual/media-management/working-with-images-and-files.md) + * [Cropping Images](tutorials/editors-manual/media-management/cropping-images.md) + * [Tips & Tricks](tutorials/editors-manual/tips-and-tricks/README.md) + * [Refreshing the Tree View](tutorials/editors-manual/tips-and-tricks/working-with-folders.md) + * [Audit Trail](tutorials/editors-manual/tips-and-tricks/audit-trail.md) + * [Notifications](tutorials/editors-manual/tips-and-tricks/notifications.md) + * [Preview Pane Responsive View](tutorials/editors-manual/tips-and-tricks/preview-pane-responsive-view.md) + * [Session Timeout](tutorials/editors-manual/tips-and-tricks/session-timeout.md) +* [Multisite Setup](tutorials/multisite-setup.md) +* [Member Registration and Login](tutorials/members-registration-and-login.md) +* [Custom Views for Block List](tutorials/creating-custom-views-for-blocklist.md) +* [Connecting Umbraco Forms and Zapier](tutorials/connecting-umbraco-forms-and-zapier.md) +* [Creating an XML Sitemap](tutorials/creating-an-xml-site-map.md) +* [Implement Custom Error Pages](tutorials/custom-error-page.md) +* [Create a custom maintenance page](tutorials/create-a-custom-maintenance-page.md) +* [Creating a backoffice API](tutorials/creating-a-backoffice-api/README.md) + * [Documenting your controllers](tutorials/creating-a-backoffice-api/documenting-your-controllers.md) + * [Adding a custom Swagger document](tutorials/creating-a-backoffice-api/adding-a-custom-swagger-document.md) + * [Versioning your API](tutorials/creating-a-backoffice-api/versioning-your-api.md) + * [Polymorphic output in the Management API](tutorials/creating-a-backoffice-api/polymorphic-output-in-the-management-api.md) + * [Umbraco schema and operation IDs](tutorials/creating-a-backoffice-api/umbraco-schema-and-operation-ids.md) + * [Access policies](tutorials/creating-a-backoffice-api/access-policies.md) +* [Extending the Help Menu](tutorials/extending-the-help-menu.md) +* [Downloadable content](tutorials/downloadable-content/README.md) + * [YouTube: Create a simple Umbraco Website](tutorials/downloadable-content/youtube-create-a-simple-umbraco-website.md) diff --git a/17/umbraco-cms/customizing/development-flow/README.md b/17/umbraco-cms/customizing/development-flow/README.md new file mode 100644 index 00000000000..0f7dc398361 --- /dev/null +++ b/17/umbraco-cms/customizing/development-flow/README.md @@ -0,0 +1,131 @@ +--- +description: Learn about the recommended development environment to extend Umbraco +--- + +# Setup Your Development Environment + +This article will take you through setting up everything you need to start building extensions and packages for Umbraco. + +## Required Software + +Make sure you have followed the [requirements](../../fundamentals/setup/requirements.md) article, especially having installed the following on your machine: +* [Node.js version 22.15.0 (Long-Term Support)](https://nodejs.org/en) and higher + +{% hint style="info" %} +Use Node Version Manager (NVM) for [Windows](https://github.com/coreybutler/nvm-windows) or [Mac/Linux](https://github.com/nvm-sh/nvm) to manage the Node.js versions. +{% endhint %} + +## Package Setup + +### App_Plugins + +Extensions such as JavaScript, CSS, and manifests, will go into a folder called `App_Plugins`. If you do not have this folder, you can create it at the root of your Umbraco project. + +{% hint style="info" %} +You can include the `App_Plugins` folder in the `wwwroot` folder of a Razor Class Library (RCL) project, but it is not required. +{% endhint %} +### Source Code + +The source code for your extensions should ideally be placed in a different project. You can make great use of a [Razor Class Library (RCL) with static assets](https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-8.0\&tabs=visual-studio#create-an-rcl-with-static-assets) for this purpose. This will make it easier to maintain and test your code. You can create a new project in the root of your Umbraco project, or you can create a new project in a separate folder. + +### Bundling + +If you are using a bundler like Webpack or Vite, you can configure it to output its files to a folder that Umbraco can see. If you have put your files directly in Umbraco project, you need to copy the compiled files over to the `App_Plugins` folder. + +With a Razor Class Library (RCL) project, you should instead configure your bundler to copy the files over to the `wwwroot` folder. You can then map your RCL project back to the `App_Plugins` web path, so Umbraco can read your files. You can do this by setting the `StaticWebAssetBasePath` in your `csproj` file: + +{% code title="MyExtension.csproj" lineNumbers="true" %} +```xml + + + + App_Plugins/MyExtension + + + +``` +{% endcode %} + +### Dependencies + +You can use any package manager you like to install dependencies. We recommend using NPM or Yarn. You can install packages by running the command: + +```bash +npm install -D +``` + +This will install the package and save it to your `package.json` file. + +You need to setup a `package.json` file if you don't have one already. You can do this by running the command: + +```bash +npm init -y +``` + +{% hint style="warning" %} +Make sure that you do not install any NPM dependencies directly into the `App_Plugins` folder. This can cause issues with Build and Publish processes in MSBuild. Always install dependencies in a separate folder and use a bundler to copy the compiled files over to the `App_Plugins` folder. +{% endhint %} + +### TypeScript Setup + +Umbraco publishes an NPM package called `@umbraco-cms/backoffice` that holds typings and other niceties to build extensions. + +{% hint style="warning" %} +Ensure that you install the version of the Backoffice package compatible with your Umbraco installation. You can find the appropriate version on the [@umbraco-cms/backoffice npm page](https://www.npmjs.com/package/@umbraco-cms/backoffice). +{% endhint %} + +You can install this package by running the command: + +```bash +npm install -D @umbraco-cms/backoffice@x.x.x +``` + +This will add a package to your devDependencies containing the TypeScript definitions for the Umbraco Backoffice. + +**TSConfig** + +Make sure to configure your TypeScript compiler so it includes the Global Types from the Backoffice. This enables you to utilize the declared Extension Types. If your project is using other Packages that provide their Extension Types, list these as well. + +In your `tsconfig.json` file, add the array `types` inside `compilerOptions`, with the entry of `@umbraco-cms/backoffice/extension-types`: + +```json +{ + "compilerOptions": { + ... + "types": [ + "@umbraco-cms/backoffice/extension-types" + ] + } +} +``` + +**Take extra care when using Vite** + +It is important that this namespace is ignored in your bundler. If you are using Vite, you can add the following to your `vite.config.ts` file: + +```ts +import { defineConfig } from "vite"; + +export default defineConfig({ + // other config + // ... + // add this to your config + build: { + rollupOptions: { + external: [/^@umbraco/], + }, + } +}); +``` + +This ensures that the Umbraco Backoffice package is not bundled with your package. + +Read more about using Vite with Umbraco in the [Vite Package Setup](vite-package-setup.md) article. + +## Visual Studio Code + +If you're using Visual Studio Code we recommend the extension called [Lit-Plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) to get IntelliSense for Lit Elements and Umbraco UI Library Components. + +## What's Next? + +Now that you have prepared your development environment, start building your Umbraco extensions. Read the article on [Umbraco Extension Template](./umbraco-extension-template.md) to set all this up. diff --git a/17/umbraco-cms/customizing/development-flow/umbraco-extension-template.md b/17/umbraco-cms/customizing/development-flow/umbraco-extension-template.md new file mode 100644 index 00000000000..1f32b8c0d37 --- /dev/null +++ b/17/umbraco-cms/customizing/development-flow/umbraco-extension-template.md @@ -0,0 +1,119 @@ +--- +description: Use the `umbraco-extension` .NET template to create a new Umbraco extension. +--- + +# Umbraco Extension Template + +Umbraco provides a .NET template to help you get started with building extensions for the Umbraco backoffice. This template sets up a new project with all the necessary files and configurations to build an extension. The template is called `umbraco-extension` and can be used to create a new Umbraco extension project with a single command. + +## Prerequisites +- [.NET SDK](https://dotnet.microsoft.com/download) version 9.0 or later +- [Node.js](https://nodejs.org/en/download/) version 22 or later + +## Install the Umbraco Extension Template +To install the Umbraco extension template, run the following command in your terminal: + +```bash +dotnet new install Umbraco.Templates +``` + +This command installs both the `umbraco` and `umbraco-extension` templates, which you can use to create new Umbraco and Umbraco extension projects. If a new Umbraco project has previously been created using `dotnet new umbraco`, the templates may already be installed. + +## Create a New Umbraco Extension +To create a new Umbraco extension project, run the following command in your terminal. It should be executed in a folder where you want to create the new project, for example in the root of your solution: + +```bash +dotnet new umbraco-extension -n MyExtension -ex +``` + +This command creates a new folder called `MyExtension` with the following files and folders: +- `MyExtension.csproj`: The project file for the extension. +- `Constants.cs`: A file containing constants for the extension. +- `Client`: A folder containing the source code for the extension, a `package.json` file, a `tsconfig.json` file, and the `vite.config.ts` configuration file. +- `README.md`: A readme file with instructions on how to build and run the extension. + +The `-ex` flag indicates that you want to include examples of how to use the extension. This flag is optional, but it is recommended to include it if you are new to building extensions for Umbraco. It will additionally give you: + +- `Composers`: A folder containing an example composer that registers a custom Swagger API. +- `Controllers`: A folder containing an example API controller for a dashboard. +- `Client/src/api`: A folder containing an example API client that calls the API controller. +- `Client/src/dashboards`: A folder containing an example dashboard Web Component that uses the API client. + +After setup, the dashboard appears in the main **Content** section of the Backoffice. + +### Add the Extension to an Umbraco Project + +To include the extension in your Umbraco project, you need to add a reference to the extension project in your Umbraco project. + +#### Option 1: Via Visual Studio + +1. Right-click the **Dependencies** node in the Umbraco project. +2. Select **Add Reference**. +3. Choose the `MyExtension` project. +4. Click **OK**. + +#### Option 2: Via CLI +Run the following command in the root folder of your Umbraco project: + +```bash +dotnet add reference ../MyExtension/MyExtension.csproj +``` + +This command adds a reference to the `MyExtension` project in your Umbraco project. You can then build your Umbraco project and see the extension in action. + +## Build and Run the Extension + +To build and run the extension, install the dependencies and start the Vite development server. To do this, run the following commands in the `Client` folder of your extension project: + +```bash +npm install +npm run build +``` + +{% hint style="info" %} +The project also builds automatically when running the Umbraco project. To start the Vite development server in watch mode, run the following command: + +```bash +npm run watch +``` +{% endhint %} + +This command compiles the TypeScript files and copies them over to the `wwwroot` output folder. Once complete, run the Umbraco project to view the extension in action. + +## Publish the Project + +The output files are automatically copied to the `wwwroot` folder of your Umbraco project. They are also included in the publishing process when you publish your Umbraco project. You can publish your Umbraco project using the following command: + +```bash +dotnet publish --configuration Release +``` + +## Publish as a Package + +To publish your extension as a package, create a NuGet package. Run the following command in the root folder of your extension project: + +```bash +dotnet pack --configuration Release +``` + +This command creates a NuGet package in the `bin/Release` folder of your extension project. You can then publish this package to a NuGet feed or share it with others. + +The `umbraco-extension` template is opinionated until a certain point. It is a starting point for building extensions for the Umbraco backoffice. The template includes a basic structure and configuration for building extensions, but you can customize it to fit your needs. You can add additional files, folders, and configurations as needed. + +To publish your extension as an Umbraco Package, you need some additional files. For details, see the [Umbraco Package](../../customizing/umbraco-package.md) article. + +### The Opinionated Starter Kit + +Another option is to use the [Opinionated Umbraco Package Starter Template](https://github.com/LottePitcher/opinionated-package-starter). This is a template that includes all the files and configurations needed to build an Umbraco package. It builds on top of the `umbraco-extension` template and includes additional files and configurations for building Umbraco packages. This template is a great starting point for building Umbraco packages and includes everything you need to get started. + +To install this template, run the following command in your terminal: + +```bash +dotnet new install Umbraco.Community.Templates.PackageStarter +``` + +To create a new package project, run the following command: + +```bash +dotnet new umbracopackagestarter -n YourPackageName -an "Your Name" -gu "YourGitHubUsername" -gr "YourGitHubRepoName" +``` diff --git a/17/umbraco-cms/customizing/development-flow/vite-package-setup.md b/17/umbraco-cms/customizing/development-flow/vite-package-setup.md new file mode 100644 index 00000000000..0afe7f7db7e --- /dev/null +++ b/17/umbraco-cms/customizing/development-flow/vite-package-setup.md @@ -0,0 +1,219 @@ +--- +description: Get started with a Vite Package, setup with TypeScript and Lit +--- + +# Vite Package Setup + +Umbraco recommends building extensions with a setup using TypeScript and a build tool such as Vite. Umbraco uses the library Lit for building web components which we will use throughout this guide. + +{% hint style="info" %} +These are general recommendations for working with and building extensions for the Umbraco backoffice. You can use any framework or library of your choice. For Umbraco's recommended approach, see the [Umbraco Extension Template](./umbraco-extension-template.md). +{% endhint %} + +## Before You Begin + +Make sure to read the [Setup Your Development Environment](./) article before continuing. + +## Create a Vite Package + +Vite comes with a set of good presets to get you quickly up and running with libraries and languages. For example: Lit, Svelte, and Vanilla Web Components with both JavaScript and TypeScript. + +1. Open your terminal and navigate to the folder where you want to create the new Vite package. +2. Run the following command: + +```bash +npm create vite@latest +``` + +This command starts a setup prompt. + +For this tutorial, it is recommended to use the names given below. However, feel free to choose other names if preferred. + +3. When prompted: + * Enter **client** as the **Project Name**. + * Select **Lit** as the framework. + * Select **TypeScript** as the variant. + + This creates a new folder called **client** with your project files. + +{% hint style="info" %} + +For Windows environments the command should be slightly different:: + +```typescript +npm create vite@latest client --- --template lit-ts +``` + +or you will still see the interactive prompts, especially when using PowerShell. + +{% endhint %} + +4. Navigate into the new **client** folder and install the packages: + +```bash +cd client +npm install +``` + +{% hint style="warning" %} +Before proceeding, ensure that you install the version of the Backoffice package compatible with your Umbraco installation. You can find the appropriate version on the [@umbraco-cms/backoffice npm page](https://www.npmjs.com/package/@umbraco-cms/backoffice). +{% endhint %} + +5. Install the Backoffice package using the following command, where `x.x.x` should be replaced with your Umbraco version: + +```bash +npm install -D @umbraco-cms/backoffice@x.x.x +``` + +6. To avoid installing Umbraco’s sub-dependencies such as the entire Monaco Editor, use the `--legacy-peer-deps` flag: + + ```bash +npm install --legacy-peer-deps -D @umbraco-cms/backoffice@x.x.x + ``` + +This disables IntelliSense for external references but keeps the install lean. + +7. Open the `tsconfig.json` file. +8. Add the array `types` inside `compilerOptions`, with the entry of `@umbraco-cms/backoffice/extension-types`: + +```json +{ + "compilerOptions": { + ... + "types": [ + "@umbraco-cms/backoffice/extension-types" + ] + } +} +``` + +9. Create a new `vite.config.ts` file in the **client** folder: + +{% code title="vite.config.ts" lineNumbers="true" %} +```ts +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + lib: { + entry: "src/my-element.ts", // your web component source file + formats: ["es"], + }, + outDir: "../App_Plugins/client", // all compiled files will be placed here + emptyOutDir: true, + sourcemap: true, + rollupOptions: { + external: [/^@umbraco/], // ignore the Umbraco Backoffice package in the build + }, + }, + base: "/App_Plugins/client/", // the base path of the app in the browser (used for assets) +}); +``` +{% endcode %} + +The `outDir` parameter specifies where the compiled files are placed. In this example, they are stored in the `App_Plugins/client` folder. If you are working with a different structure, such as a Razor Class Library (RCL) project, update this path to `wwwroot`. + +This alters the Vite default output into a **library mode**, where the output is a JavaScript file with the same name as the `name` attribute in `package.json`. The name is `client.js` if you followed this tutorial with no changes. + +The source code that is compiled lives in the `src` folder of your package folder and that is where you can see a `my-element.ts` file. You can confirm that this file is the one specified as our entry on the Vite config file that we recently created. + +The `build:lib:entry` parameter can accept an array which will allow you to export multiple files during the build. You can read more about [Vite's build options here](https://vitejs.dev/config/build-options.html#build-lib). + +10. Build the `ts` file in the **client** folder: + +```bash +npm run build +``` + +## Watch for changes and build + +To continuously work on the package and have each change built, add a `watch`script in your `package.json` with `vite build --watch`. + +The example below indicates where in the structure this change should be implemented: + +{% code title="package.json" lineNumbers="true" %} +```json +{ + "name": "client", + ... + "scripts": { + "watch": "vite build --watch" + ... + }, + ... +``` +{% endcode %} + +Run `npm run watch` in the terminal. + +## Umbraco Package declaration + +Declare your package to Umbraco via a file called `umbraco-package.json`. This should be added in the `public` folder under the root of your package. Once built the `umbraco-package.json` file should be located at `/App_Plugins/` or `/App_Plugins/{YourPackageName}` for Umbraco to detect it. + +This example declares a Dashboard as part of your Package, using the Vite example element. + +{% code title="client/public/umbraco-package.json" lineNumbers="true" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Dashboard", + "version": "0.1.0", + "extensions": [ + { + "type": "dashboard", + "alias": "My.Dashboard.MyExtension", + "name": "My Dashboard", + "element": "/App_Plugins/client/client.js", + "elementName": "my-element", + "meta": { + "label": "My Dashboard", + "pathname": "my-dashboard" + } + } + ] +} +``` +{% endcode %} + +{% hint style="info" %} +Umbraco needs the name of the element that will render as default when our dashboard loads. + +* This is specified in the **manifest** as the `elementName`. +* Another approach would be to define your default element in the TS code. To do this, in the `src/my-element.ts` add **`default`** to your `MyElement` class in the file like so: + +```ts +export default class MyElement extends LitElement { +``` +{% endhint %} + +Learn more about the abilities of the manifest file in the [Umbraco Package Manifest](../umbraco-package.md) article. + +#### Testing your package + +To test your package, run your site. + +Before doing this, make sure to run `npm run build` to compile your TypeScript files and copy them to the `App_Plugins/client` folder. + +{% hint style="warning" %} +If you try to include some of these resources via Visual Studio (VS), then make sure not to include TypeScript files. Otherwise, VS will try to include a few lines on your `.csproj` file to compile the TypeScript code that exists in your project folder. When you run your website, VS will try to compile these files and fail. +{% endhint %} + +The final result looks like this: + +

My dashboard

+ +In the `src/my-element.ts` file, update the `styles` property to make any styling changes. You can change the `background-color` of the `button` to white so it is more visible: + +```css +button { + background-color: white; +} +``` + +## Summary + +With this, you have set up your Package and created an Extension for the Backoffice. + +In more advanced cases, you can add more elements to your package and create more complex extensions. In that case, you can benefit greatly from creating another project in your solution to hold the files. This way, you can keep your solution clean and organized. We recommend creating a [Razor Class Library (RCL)](https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-8.0\&tabs=visual-studio#create-an-rcl-with-static-assets) for this purpose. You can read more about this in the [Development Flow](./#source-code) article. + +This Dashboard appears in all sections and does not do much. To extend it to interact with the Umbraco Backoffice, follow the tutorial on [Creating Your First Extension](../../tutorials/creating-your-first-extension.md). diff --git a/17/umbraco-cms/customizing/extending-overview/README.md b/17/umbraco-cms/customizing/extending-overview/README.md new file mode 100644 index 00000000000..007f5a98fff --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/README.md @@ -0,0 +1,26 @@ +--- +description: >- + The backoffice architecture is based on Extensions. Everything in the UI is + Extensions which makes almost any parts of the UI extendable. Enabling you to + append, replace, or remove parts. +--- + +# Extensions Overview + +The following screenshot highlights some elements that are extensions. However, a single image cannot fully illustrate this, so we recommend exploring the options in more detail in the [Extension Types](./#extension-types) article. + +
+ +In this section, you can find the common terms, concepts and guides used to extend the Umbraco backoffice. + +## [Extension Registry](extension-registry/) + +How to register extensions or manipulate others. + +## [Extension Types](extension-types/) + +An overview of the different ways to append functionality. + +## [Extension Conditions](extension-conditions.md) + +Make your extension appear only when certain conditions are met. diff --git a/17/umbraco-cms/customizing/extending-overview/custom-extension-type.md b/17/umbraco-cms/customizing/extending-overview/custom-extension-type.md new file mode 100644 index 00000000000..029ab2bb9c1 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/custom-extension-type.md @@ -0,0 +1,23 @@ +# Custom Extension types + +The extension registry is an open system, which can hold any Extension Manifest Type. This article describes how you can declare your types.\ +Types can be declared for re-useability/maintainability or to open up for other package extensions. + +## Manifest Type Declaration + +A Manifest Type is declared via a TypeScript Interface, like shown below: + +```typescript +import type { ManifestBase } from '@umbraco-cms/backoffice/extension-api'; + +export interface ManifestPreviewAppProvider extends ManifestBase { + type: 'myPrefixedExtensionType'; +} + +// Declare the Manifest Type in the global UmbExtensionManifestMap interface: +declare global { + interface UmbExtensionManifestMap { + MyPrefixedExtensionManifest: MyExtensionManifestType; + } +} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-conditions.md b/17/umbraco-cms/customizing/extending-overview/extension-conditions.md new file mode 100644 index 00000000000..f6a867a39da --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-conditions.md @@ -0,0 +1,53 @@ +--- +description: Learn how to use Extension Conditions when working with the Umbraco backoffice. +--- + +# Extension Conditions + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Extension Manifest Conditions enable you to declare requirements for an Extension before it becomes available. + +## Utilizing Conditions in your Manifest + +Conditions are referenced via their alias. The Declaration of a Condition is shown in the following example: + +```typescript +const manifest = { + type: 'workspaceView', + ... + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + }, + ], +}; +``` + +By declaring a condition the extension will become available only once the condition is permitted. + +The example above requires the nearest Workspaces Alias to be equal to `'Umb.Workspace.Document'`. + +When declaring multiple conditions all of them must be permitted for the extension to be available. + +## Built-in Conditions Types + +For a list of available options, see the [Built-in Conditions Types](extension-types/condition.md#built-in-conditions-types) section. + +## Condition Configuration + +The conditions are defined as an array of condition configurations. Each entry can contain the following properties: + +* `alias`- The alias of the condition to utilize. +* `...` - The rest of the properties of the object are specific to the condition configuration. + +## Learn more + +Learn about built-in conditions and how to create your own: + +{% content-ref url="extension-types/condition.md" %} +Condition Extension Type +{% endcontent-ref %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-kind.md b/17/umbraco-cms/customizing/extending-overview/extension-kind.md new file mode 100644 index 00000000000..7d6b711c1c9 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-kind.md @@ -0,0 +1,56 @@ +--- +description: Learn how to use the Kind extension in your manifest files when extending the Umbraco CMS backoffice. +--- + +# Extension Kind + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The **Extension Manifest Kind** is used to declare a preset configuration that other extensions can inherit. It ensures maintainability and consistency when creating extensions for the Umbraco CMS backoffice. By using a Kind, developers can reuse predefined settings, which reduces redundancy across extensions. + +When a Kind is applied, the extension's manifest inherits the fields defined in the Kind. This approach prevents the need to repeat configuration details across multiple extensions. + +## Manifest Kind Declaration + +A **Kind** is declared in the `kind` field of the manifest, which is part of the extension registration process. The declaration is linked to a specific extension type. + +```typescript +const manifest = { + type: 'headerApp', // The type of the extension + kind: 'button', // The kind alias to inherit settings from + ... +}; +``` + +By setting the `kind` field, the extension automatically inherits all properties associated with that **Kind**. This is useful when you want to standardize a component (like a button) across multiple extensions. + +## Using the Kind for Inheritance + +A Kind not only defines the basic configuration but may also require additional metadata to fully configure the element or component. + +### Example: Using the Button Kind in a Header App + +```typescript +const manifest = { + type: 'headerApp', + kind: 'button', + name: 'My Header App Example', + alias: 'My.HeaderApp.Example', + meta: { + label: 'My Example', + icon: 'icon-home', + href: '/some/path/to/open/when/clicked', + }, +}; +``` + +In this example: + +- The `kind: 'button'` inherits all default settings from the **Button Kind**. +- The `meta` object is added to configure additional properties, such as the button's label, icon, and the URL to open when clicked. + +The Kind allows you to extend existing functionality and tailor it to specific needs while maintaining consistency. + +For a deeper dive into Kind and how to create your own, see the [Kind](extension-types/kind.md) article. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-registry/README.md b/17/umbraco-cms/customizing/extending-overview/extension-registry/README.md new file mode 100644 index 00000000000..7b301272765 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-registry/README.md @@ -0,0 +1,22 @@ +--- +description: >- + Almost any UI in the Backoffice is an extension managed by the Extension Registry. +--- + +# Extension Registry +The Umbraco backoffice is built with extensibility in mind. The backoffice without extensions is more or less a blank canvas that is build out using extensions. These extensions dictate how the backoffice functions and looks. All visual elements in an Umbraco installation, like the sections, menus, trees and buttons, are extensions. But extensions also dictate behaviour and the editing experience. So everything in the backoffice is governed (and extendable) by extensions. + +{% hint style="info" %} +You can see which extensions are registered in the backoffice by going to Settings > Extensions Insights. +{% endhint %} + +All extensions are registered in the extension registry. The registry can be manipulated at any time, meaning you can add or remove extensions at runtime. You as a developer have the same possibilities as an Umbraco HQ developer, which means what HQ can do, you can do. This also means that you can change almost everything that is by default present in Umbraco. + +## [Introduction to a Extension Manifest](extension-manifest.md) +An Extension Manifest is a declaration of what you want to register in the Umbraco backoffice. This articles handles the layout and requirements of an Extension Manifest. + +## [Register an extension](extension-registry.md) +This article handles how to register an extension using an umbraco-package.json file. + +## [Change an existing extension](replace-exclude-or-unregister.md) +Once you understand how to declare your own, you may want to replace or remove existing ones. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-registry/extension-manifest.md b/17/umbraco-cms/customizing/extending-overview/extension-registry/extension-manifest.md new file mode 100644 index 00000000000..9db6641c5e6 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-registry/extension-manifest.md @@ -0,0 +1,44 @@ +--- +description: Learn about the different methods for declaring an Extension Manifest. +--- + +# Extension Manifest +This page explains what an Extension Manifest for a Umbraco backoffice extension is. It outlines the manifest structure, required fields, and optional features used across types. + +## What is an Extension Manifest? +Umbraco reads the extension manifest to register the extension in the Extension Registry. +Each extension is of a certain type and this determines the required fields of the manifest and its available capabilities. +An Extension Manifest declares a single backoffice extension along with its configuration. + +## Extension Manifest Format +Some extensions need extra assets, such as a JavaScript file with a Web Component. + +The abilities of the extensions rely on the specific extension type. The type sets the scene for what the extension can do and what it needs to be utilized. Some extension types can be made purely via the manifest, like a section or menu item. Other types require files, like a JavaScript file containing a Web Component, like a custom property editor. +An Extension Manifest has a strict format where some properties are required and some depend on the Extension Type. An Extension Manifest can be written as a JavaScript or JSON object. You can learn more about this when [registering an extension](register-extensions.md). +### Required Manifest properties +A minimal Extension Manifest looks like this: + +```json +{ + "type": "...", + "alias": "my.customization", + "name": "My customization" +} +``` + +These fields are all required and have the following meaning: + +* `type` — The type defines the purpose of the extension. Umbraco has many [extension types](../extension-types) available. +* `alias` — Unique identifier for this manifest. Prefix it with something that makes your extension unique. For example: _FictiveCompany.MyProject.Dashboard.Overview_. +* `name` — Representational name of this manifest. This name does not need to be unique, but this can be beneficial when debugging extensions. This name also shows up in the Extensions Insights in the backoffice of Umbraco. For example: _My Fictive Company Overview Dashboard_. + +### Additional Manifest properties +Most extension types support the use of the following generic features for their Manifest: + +* `weight` - Define a weight to determine the importance or visual order of this extension. A higher weight gives a more prominent position. For instance, for a dashboard it determines its order between other dashboards. +* `overwrites` - If you want to omit an existing extension, then define one or more Extension Aliases that this extension should omit when presented. Read more in [Replace, Exclude or Unregister extensions](replace-exclude-or-unregister.md). +* `conditions` - Define one or more conditions that must pass for the extension to become available. For instance, don't show a section if you don't have the proper rights. Read more in [Extension Conditions](../extension-conditions.md). +* `kind` - Some extension types can reference a predefined `kind`. By specifying a `kind`, the manifest inherits the `kind`'s properties. This allows for reuse of predefined settings. See [Extension Kind](../extension-kind.md). +* `meta` - Many Extension Types require additional information declared as part of a `meta` field. It depends on the Extension Type what is required. For instance label and icon of a menu item. + +For more information, see an overview of all possible [Extension Types](../extension-types/) and their requirements. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-registry/register-extensions.md b/17/umbraco-cms/customizing/extending-overview/extension-registry/register-extensions.md new file mode 100644 index 00000000000..0e46a5e2455 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-registry/register-extensions.md @@ -0,0 +1,120 @@ +--- +description: >- + You can bring new UI or additional features to the Backoffice by + registering an Extension via an Extension Manifest. +--- + + +# Register Extensions +Making extensions to either an Umbraco project or a package requires an umbraco-package.json file. This JSON file is the starting point for any extension. + +## Umbraco-package.json +To get extensions registered in Umbraco, you need to have an `umbraco-package.json` file. This file must be located in or in a subfolder of either the `App_Plugins` folder or the `wwwroot` folder. It's recommended to place the file in `App_Plugins/#YOUR_EXTENSION_NAME#/umbraco-package.json`, or in `wwwroot/App_Plugins/#YOUR_EXTENSION_NAME#/umbraco-package.json` for packages and Razor Class Libraries. Umbraco scans for these files on boot and reads the [`Extension Manifests`](extension-manifest.md) that are present in the file to register the extensions. + +{% hint style="info" %} +Extensions can also work outside of the context of a package. +{% endhint %} + +{% code title="umbraco-package.json" %} +```json +{ + "name": "My Customizations", + "extensions": [ + { + "type": "...", + "alias": "my.customization.extension1", + "name": "My customization extension 1" + ... + }, + ... + ] +} +``` +{% endcode %} + + +When writing the Umbraco Package Manifest, you can use the JSON schema located in the root of your Umbraco project. This file is called `umbraco-package-schema.json`. + +{% code title="umbraco-package.json" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Customizations", + "extensions": [ + ... + ] +} +``` +{% endcode %} + + +There are two additional, optional properties that can be useful: + +* `id` - a unique identifier of the package. If you are creating a NuGet package, use this value as the id. +* `version` - the version of the package that is displayed in the backoffice in the overview of installed packages. This is also used for package migrations. + + +This is an example of a full `umbraco-package.json` that registers two localization extensions: + +```json +{ + "$schema": "../../umbraco-package-schema.json", + "id": "MyCustomizations", + "name": "My Customizations", + "version": "16.0.0", + "extensions": [ + { + "type": "localization", + "alias": "MyCustomizations.Localize.EnUS", + "name": "English", + "meta": { + "culture": "en" + }, + "js": "/App_Plugins/MyCustomizations/localization/en.js" + }, + { + "type": "localization", + "alias": "MyCustomizations.Localize.DkDk", + "name": "Danish", + "meta": { + "culture": "dk" + }, + "js": "/App_Plugins/MyCustomizations/localization/dk.js" + } + ] +} +``` + + +## Advanced Registration +### The Bundle Approach +Instead of registering each manifest in the `umbraco-package.json`, you can have multiple manifests and build them into a bundle. You then register this bundle in a single `bundle` extension. In larger projects with a lot of extensions, this allows you to keep your `umbraco-package.json` file cleaner. Read more in the [bundle approach](../extension-types/bundle.md). + +### The Entry Point Approach +The Entry Point is an extension that executes a method on startup. You can use this for different tasks, such as performing initial configuration and registering other Extension Manifests. Read more in [the entry point approach](../extension-types/backoffice-entry-point.md). + +### Registration with JavaScript on the Fly +In some cases, extensions are not static and cannot be registered in the umbraco-package.json or in a bundle. Here are some examples of these cases: + +- your manifest might be defined based on information from the server +- you might generate the manifests server side based on data in the database. + +In cases such as these, you need to register extensions on the fly. + + +The following example shows how to register an Extension Manifest via JavaScript/TypeScript code: + +```typescript + +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +const manifest = { + type: '...', + // ... +}; + +umbExtensionsRegistry.register(manifest); +``` + + +When and where you execute this code depends on your situation. In many cases, it makes sense to execute this on boot, using the [entry point approach](../extension-types/backoffice-entry-point.md). diff --git a/17/umbraco-cms/customizing/extending-overview/extension-registry/replace-exclude-or-unregister.md b/17/umbraco-cms/customizing/extending-overview/extension-registry/replace-exclude-or-unregister.md new file mode 100644 index 00000000000..cd8de5eb9a4 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-registry/replace-exclude-or-unregister.md @@ -0,0 +1,82 @@ +--- +description: >- + You may want to replace or completely remove an extension. Depending on your + interest, 3 different options are available. +--- + + +# Replace, Exclude or Unregister +Besides adding extensions to Umbraco, sometimes you want to change what is already there. You can replace extensions with your own and exclude or unregister extensions. + + +## Replace +You can replace an existing extension by another one. +You can do this by defining the `overwrites` property in your [Extension Manifest](extension-manifest.md) with one Extension Alias. For multiple `overwrites` you can provide the Extension Aliases that need to be replaced as an array. + + + + +This example overrides the `save and preview` button with an external "preview" button (single overwrite): + +```typescript +const manifest = { + type: 'workspaceAction', + alias: 'my.WorkspaceAction.ExternalPreview', + name: 'My workspace action for external preview', + overwrites: 'Umb.WorkspaceAction.Document.SaveAndPreview' + ... +}; +``` + + +This example overrides both the `save and preview` button as well as the `save` button with an external "preview" button (multiple overwrite): + +```typescript +const manifest = { + type: 'workspaceAction', + alias: 'my.WorkspaceAction.ExternalPreview', + name: 'My workspace action for external preview', + overwrites: ['Umb.WorkspaceAction.Document.SaveAndPreview', 'Umb.WorkspaceAction.Document.Save'] + ... +}; +``` + + +If your extension has conditions, the overwritten extensions will only be hidden when your extension is displayed. This means that the overwrites only have an effect if all the conditions are permitted and the extensions are displayed at the same spot. + + +## Exclude +When you exclude an extension, the extension will never be displayed. This allows you to permanently hide, for example, a menu or a button. This does not unregister the extension, but rather flags it as excluded. This also means that no one else can register an extension with the same alias as the excluded extension. + + +{% hint style="warning" %} +Currently, it is not possible to un-exclude extensions once excluded. +{% endhint %} + + +The following JavaScript code hides the `Save and Preview` button from the Document Workspace. + +```typescript +import { UmbExtensionRegistry } from '@umbraco-cms/backoffice/extension-api'; + +UmbExtensionRegistry.exclude('Umb.WorkspaceAction.Document.SaveAndPreview'); +``` + +When and where you execute this code depends on your situation. In many cases, it makes sense to execute this on boot, using the [entry point approach](../extension-types/backoffice-entry-point.md). + + +## Unregister +You can also choose to unregister an extension. You should only use this on extensions you registered yourself and have control over. Otherwise, you might try to remove an extension before it is registered. A use case for this, is if you temporarily registered an extension and you want to remove it again. + +In other cases, you can use the `overwrites` or `exclude` option. The difference with the `exclude` approach is that unregistering removes the extension from the Extension Registry. This allows you to re-register extensions with the same alias. + +```typescript +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +umbExtensionsRegistry.unregister('My.WorkspaceAction.AutoFillWithUnicorns'); +``` + + +When and where you execute this code depends on your situation. In many cases, it makes sense to execute this on boot, using the [entry point approach](../extension-types/backoffice-entry-point.md). + + diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/README.md new file mode 100644 index 00000000000..6cfd32a3077 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/README.md @@ -0,0 +1,199 @@ +--- +description: >- + An overview of general extension types available in the Umbraco backoffice. +--- + +# Extension Types + +## General Features + +Extension Types in Umbraco allow developers to extend and customize the behavior of the backoffice. Each type provides unique functionality, such as creating custom dashboards, enhancing entity actions, or enabling localization. Learn more about the shared properties and overall structure in the [Extension Manifest](../extension-registry/extension-manifest.md) article. + +## Common Extension Types + +The **Umbraco backoffice** provides **Extension Types** designed to meet a variety of customization needs. These include extensions tailored for specific functionalities, as well as general-purpose extensions for broader use cases. + +### [App Entry Point](app-entry-point.md) + +The `App Entry Point` extension type is used to execute JavaScript when Umbraco starts up. The code will run before the user has logged in or the backoffice has initialized. + +### [Backoffice Entry Point](backoffice-entry-point.md) + +The `backofficeEntryPoint` extension type is used to execute JavaScript upon initialization of the backoffice. This extension type provides lifecycle hooks (startup, teardown) for extension developers to customize backoffice behavior. + +### [Block Custom View](block-custom-view.md) + +The `blockEditorCustomView` extension type is used to define a custom web component for representing blocks inside the Umbraco block grid property editor. + +### [Bundle](bundle.md) + +The `bundle` extension type is used to aggregate multiple extension manifests into a single entity, which will be registered at startup. + +### [Dashboards](dashboard.md) + +The `dashboard` extension type enables extension authors to create custom informational panels that can be displayed in the Umbraco backoffice. These extensions can be added to existing Umbraco sections or to a custom section. + +### [Entity Actions](entity-actions.md) + +The `entityAction` extension type is used to create menus for operations on an entity such as a document or media item. Built-in backoffice examples include: "Trash", "Duplicate to...", "Publish" etc. + +### [Entity Bulk Actions](entity-bulk-actions.md) + +The `entityBulkAction` extension type works similarly to the **Entity Actions** extension type, but performs the actions on a selection of entities from a collection. + +### [Entity Create Option Action](entity-create-option-action.md) + +The `entityCreateOptionAction` extension type is used to provide custom entity creation actions via a dedicated modal interface. + +### [Extension Conditions](condition.md) + +Most extension types support conditions which allow extension authors to control when and where the extension is available. This type enables extension authors to define their own conditions. + +### [Global Context](global-context.md) + +The `globalContext` extension type creates a custom context of data and functions, accessible throughout the entire backoffice and the entire session. + +### [Header Apps](header-apps.md) + +The `headerApp` extension type is used to place single-purpose extensions in the top-level navigation bar. These extensions appear next to the user profile. + +### [Icons](icons.md) + +The `icons` extension type is used to make custom icon extension sets available in the Umbraco backoffice and in custom Umbraco UI components. Extension authors provide SVG files and register them using this extension type. + +### [Kinds](kind.md) + +The `kind` extension type is used to create custom extension configurations to be used as the basis of other custom extension types. They can be inherited by other extension types. + +### [Localization](localization.md) + +The `localization` extension type is used to register additional languages and files of translation strings that can be used in Umbraco backoffice extensions. + +### [Menu](menu.md) + +The `menu` extension type is used to create custom menus. These can be placed in sidebar extensions or displayed as a fly-out from a button, header, or workspace view. + +### [Modals](modals/README.md) + +The `modal` extension type is used to configure and present dialogs and sidebars within the Umbraco backoffice. + +### [Property Value Preset](property-value-preset.md) + +The `propertyValuePreset` extension type is used to customize the default value of a property editor and allow for dynamic behavior through hooks. + +### [Sections](sections/README.md) + +The `section` extension type is used to place top-level navigation items within the Umbraco backoffice. Custom Section extensions appear alongside Content, Media, Settings, and others, as seen in the purple navigation bar. + +### [Trees](tree.md) + +The `tree` extension type is used to create a hierarchical structure composed of nodes, such as documents, media extensions, or toolbar extensions. + +### [Workspaces](workspaces/README.md) + +The `workspace` extension type provides functionality that operates within specific workspace environments, such as document editing, media management, or member editing. + +## Even More Extension Types + +### [Property Level UI Permissions](../../property-level-ui-permissions.md) + +Umbraco allows system administrators to define read and write permissions on an individual property basis. `Property Level UI Permissions` can be created to define customized rules to fit any use case. + +### [Tip-Tap Extensions](../../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md) + +The Tip-Tap editor is the default text editor in Umbraco. Tip-Tap can be extended with either native extensions or toolbar button extensions. + +### [Umbraco Flavored Markup Components](../../../reference/umbraco-flavored-markdown.md) + +`Umbraco Flavored Markup (UFM) Components` are used to create descriptions and labels for entities across the backoffice. These replace the previous "Label Property Configuration" feature. Extension authors can create custom components that go beyond textual labels, including creating hooks that allow for imperative programming tasks and custom markup. + +## Extension Insights Browser + +Umbraco provides a number of additional extension types that can be used to extend the backoffice. The backoffice contains an interactive browser for exploring all available extension types. This feature also allows users to confirm that their own backoffice extensions are found and loaded by the backoffice. + +To use the Extension Insights browser, navigate to the **Settings** section of the backoffice and select **Extension Insights** from the sidebar. A comprehensive list of available types can be found in the dropdown menu to the right. + +

Backoffice extension browser

+ +## Full List of Extension Types + +These are the current types of UI Extensions: + +| Type | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| authProvider | An authentication provider for [external login](../../../reference/security/external-login-providers.md). | +| appEntryPoint | An app entry point is a JavaScript module that is executed when any app is loaded (Login, Installer, Upgrader, and Backoffice). It will never be destroyed. Read more about [Entry Points](./app-entry-point.md). | +| backofficeEntryPoint | A backoffice entry point is a JavaScript module that is executed when the backoffice is loaded. It will be destroyed when the backoffice is closed or logged out. Read more about [Entry Points](./backoffice-entry-point.md). | +| blockEditorCustomView | A custom view for a block in the block editor. | +| bundle | A bundle is a collection of other manifests that can be loaded together. You would use this in lieu of a `backofficeEntryPoint` if all you needed was to load extensions through JavaScript. | +| condition | A condition that can be used to control the visibility of other UI Extensions. Read more about [Conditions](./condition.md). | +| currentUserAction | A current user action is a button that can be added to the current user view. | +| dashboard | A dashboard is a view that can be added to any section. It is displayed in the dashboard view with tabs. Read more about [Dashboards](./dashboard.md). | +| dashboardCollection | A dashboard collection is a view that can be added to a collection. | +| dynamicRootOrigin | A dynamic root origin is a dynamic root origin that can be added to the Dynamic Root selector. | +| dynamicRootQueryStep | A dynamic root query step is a query step that can be added to the Dynamic Root selector. | +| entityAction | An entity action is a button that can be added to any entity, like a document, media, member, etc. It will be shown in the entity actions menu and in the entity actions menu. | +| entityBulkAction | An entity bulk action is a button that can be added to the bulk actions menu, which is shown when multiple entities are selected in a collection view. | +| entryPoint | (Deprecated) Old name for `backofficeEntryPoint`. | +| fileUploadPreview | A file upload preview is a component that can be used to preview files when they are uploaded in the media section. [See the default previews in Umbraco on GitHub](https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/preview/manifest.ts) | +| globalContext | A global context is a context instance that is available to all components in the Backoffice. It is used to share state between components and to provide a way to communicate between components. Read more about [Global Context](./global-context.md). | +| granularUserPermissions | A granular user permission is a permission that can be added to a user. It is used to control access to specific parts of the Backoffice. | +| headerApp | A header app is a component that can be added to the header such as a button or a link. Read more about [Header Apps](./header-apps.md). | +| healthCheck | A health check is a check that can be added to the health check dashboard. Read more about the backend side of [Health Checks](../../../reference/configuration/healthchecks.md). | +| icons | An icon is a set of icons that can be added to the icon picker. Read more in the [Icons article](./icons.md). | +| localization | A localization is a set of translations that can be added to the localization service. Read more about [Localization](../../foundation/localization.md) in the UI. | +| menu | A menu is a component that can be added to the menu bar. Read more about [Menus](./menu.md). | +| menuItem | A menu item is a component that can be added to a menu. | +| mfaLoginProvider | This type of login provider is the UI component of [Two-Factor Authentication](../../../reference/security/two-factor-authentication.md) used to enable/disable the provider. | +| modal | A modal dialog. Read more about [Modals](./modals/). | +| monacoMarkdownEditorAction | A Monaco Markdown Editor action is a button that can be added to the toolbar of the [Markdown Property Editor](../../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md). | +| packageView | A package view is an optional view that can be shown in the "Packages" section of the Backoffice. The user can navigate to this view to see more information about the package and to manage it. | +| previewAppProvider | A preview app provider is a provider that can be used to provide a preview app for the Save and Preview action on a document. | +| propertyAction | A property action is a button that can be added to the property actions menu. | +| propertyEditorSchema | A property editor schema is a model that describes a Data Editor and its properties from the backend to the UI. It is used by Property Editor UIs. Read more about [Property Editors](../../property-editors/). | +| propertyEditorUi | A property editor UI is a UI component that can be added to content types. It is used to render the UI of a Data Editor. Read more about [Property Editors](../../property-editors/). | +| searchProvider | A search provider is a provider that can be used to provide search results for the search bar in the Backoffice. | +| searchResultItem | A search result item is a component that can be added to the search results. | +| theme | A theme is a set of styles that can be added to the Backoffice. The user can select their preferred theme in the current user modal. | +| tiptapExtension | A Tiptap extension is a component that can be added to the [Rich text editor](../../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/). | +| tiptapToolbarExtension | A Tiptap toolbar extension is a component that can be added to the toolbar of the [Rich text editor](../../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/). | +| tiptapStatusbarExtension | A Tiptap status bar extension is a component that can be added to the status bar of the [Rich text editor](../../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/). | +| treeItem | A tree item that can be added to the tree. | +| tree | A tree that can be added to a section. | +| ufmComponent | This type of component is a formatter that can be added to the [Umbraco Flavoured Markdown](../../../reference/umbraco-flavored-markdown.md), which is used in property descriptions and advanced labels. | +| userProfileApp | A user profile app is a component that can be added to the current user view. | + +**Collections** + +| Type | Description | +| ---------------- | -------------------------------------------------------------------------- | +| collection | A collection to show a list of entities (documents, media, members, etc.). | +| collectionAction | A collection action is a button that can be added to a collection view. | +| collectionView | A collection view is a view that can be added to a collection. | + +**Repositories** + +| Type | Description | +| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| repository | A repository is a class that can be used to interact with a data source. It is used either by context classes or elements directly to interact with the data source. Read more about [Repositories](../../foundation/repositories.md). | + +**Sections** + +| Type | Description | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| section | A section is a section that can be added to the navigation bar of the Backoffice like the "Content" or "Media" sections that are built-in. Read more about [Sections](./sections/section.md). | +| sectionRoute | A section route is a route that can be added to a section. It is used to define the URL of the view that is displayed in the main content area of the Backoffice. | +| sectionSidebarApp | A section sidebar app that can be added to the section sidebar. Read more about [Section Sidebar Apps](./sections/section-sidebar.md). | +| sectionView | A section view is a view that can be added to a section. It is displayed in the main content area of the Backoffice. More than one view can be added to a section, and the user can switch between them. In that case, the views are displayed as tabs. Read more about [Section Views](./sections/section-view.md). | + +**Workspaces** + +| Type | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| workspace | A workspace is a component that can be added to an entity type. This is the editor you see, when you edit an entity. Read more about [Workspaces](./workspaces/README.md). | +| workspaceActionMenuItem | A workspace action menu item is a button that can be added to the workspace action menu. | +| workspaceAction | A workspace action is a button that can be added to the workspace such as the "Save" button. Read more about [Workspace Actions](./workspaces/workspace-editor-actions.md). | +| workspaceContext | A workspace context is a context instance that is available to all components in the workspace. It is used to share state between components and to provide a way to communicate between components. Read more about [Workspace Context](./workspaces/workspace-context.md). | +| workspaceFooterApp | A workspace footer app is a component that can be added to the workspace footer. | +| workspaceView | A workspace view is a view that can be added to a workspace. It is displayed in the main content area of the workspace. More than one view can be added to a workspace, and the user can switch between them. In that case, the views are displayed as tabs. Read more about [Workspace Views](./workspaces/workspace-views.md). | + diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/app-entry-point.md b/17/umbraco-cms/customizing/extending-overview/extension-types/app-entry-point.md new file mode 100644 index 00000000000..7885853f52f --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/app-entry-point.md @@ -0,0 +1,21 @@ +--- +description: >- + The App Entry Point extension type is used to run some JavaScript code before + the user is logged in. +--- + +# App Entry Point + +This manifest declares a single JavaScript file that will be loaded and run when the Backoffice starts. Additionally, the code will also run on the login screen. + +{% hint style="info" %} +See [Backoffice Entry Point](backoffice-entry-point.md) if you are looking for an Extension that runs when the user is logged in. +{% endhint %} + +It performs the same function as the `backofficeEntryPoint` extension type, but the difference is that this runs before the user is logged in. Use this to initiate things before the user is logged in or to provide things for the Login screen. + +Read more about `backofficeEntryPoint` to learn how to use it: + +{% content-ref url="backoffice-entry-point.md" %} +[backoffice-entry-point.md](backoffice-entry-point.md) +{% endcontent-ref %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/auth-provider.md b/17/umbraco-cms/customizing/extending-overview/extension-types/auth-provider.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/backoffice-entry-point.md b/17/umbraco-cms/customizing/extending-overview/extension-types/backoffice-entry-point.md new file mode 100644 index 00000000000..3bdff51100e --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/backoffice-entry-point.md @@ -0,0 +1,163 @@ +--- +description: >- + The Backoffice Entry Point extension type is used to run some JavaScript code + at startup. +--- + +# Backoffice Entry Point + +This manifest declares a single JavaScript file that will be loaded and run when the Backoffice starts. In other words, this can be used as an entry point for a package. + +{% hint style="info" %} +See [App Entry Point](app-entry-point.md) if you are looking for an Extension that runs before the user is logged in. +{% endhint %} + +The `backofficeEntryPoint` extension is also the way to go if you want to load in external libraries such as jQuery, Angular, React, etc. You can use the `backofficeEntryPoint` to load the external libraries to be shared by all your extensions. Additionally, **global CSS files** can also be used in the `backofficeEntryPoint` extension. + +**Register a Backoffice Entry Point in the `umbraco-package.json` manifest** + +{% code title="umbraco-package.json" %} +```json +{ + "name": "Name of your package", + "alias": "My.Package", + "extensions": [ + { + "type": "backofficeEntryPoint", + "alias": "My.EntryPoint", + "js": "/App_Plugins/YourFolder/index.js" + } + ] +} +``` +{% endcode %} + +**Base structure of the entry point file** + +{% hint style="info" %} +All examples are in TypeScript, but you can use JavaScript as well. Make sure to use a bundler such as [Vite](../../development-flow/vite-package-setup.md) to compile your TypeScript to JavaScript. +{% endhint %} + +{% code title="index.ts" %} +```typescript +import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; + +/** + * Perform any initialization logic when the Backoffice starts + */ +export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { + // Your initialization logic here +} + +/** + * Perform any cleanup logic when the Backoffice and/or the package is unloaded + */ +export const onUnload: UmbEntryPointOnUnload = (host, extensionRegistry) => { + // Your cleanup logic here +} +``` +{% endcode %} + +{% hint style="info" %} +The `onUnload` function is optional and can be used to perform cleanup logic when the Backoffice and/or the package is unloaded. +{% endhint %} + +## Examples + +### Register additional UI extensions in the entry point file + +{% code title="index.ts" %} +```typescript +import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; + +const manifest: UmbExtensionManifest = { + type: '', // type of extension + alias: '', // unique alias for the extension + elementName: '', // unique name of the custom element + js: '', // path to the javascript resource + meta: { + // additional props for the extension type + } +}; + +export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { + // Register the extension + extensionRegistry.register(manifest); +} + +export const onUnload: UmbEntryPointOnUnload = (host, extensionRegistry) => { + // Unregister the extension (optional) + extensionRegistry.unregister(manifest); +} +``` +{% endcode %} + +{% hint style="info" %} +If you only need to register extensions, then consider using a [bundle](bundle.md) type instead. +{% endhint %} + +### Register global CSS + +An entry point is a good place to load global CSS files for the whole application. You can do this by creating a link element and appending it to the head of the document: + +{% code title="index.ts" %} +```typescript +import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; + +export const onInit: UmbEntryPointOnInit = (host, extensionsRegistry) => { + const css = document.createElement('link'); + css.rel = 'stylesheet'; + css.href = '/App_Plugins/YourFolder/global.css'; + document.head.appendChild(css); +} +``` +{% endcode %} + +Alternatively, you can import the CSS file directly into your JavaScript file: + +{% code title="index.ts" %} +```typescript +import '/App_Plugins/YourFolder/global.css'; +``` +{% endcode %} + +## Type IntelliSense + +It is recommended to make use of the Type intellisense that we provide. + +When writing your Manifest in TypeScript, you should use the `UmbExtensionManifest` type. Read the [TypeScript setup](broken-reference/) article to make sure you have Types correctly configured. + +{% code title="index.ts" %} +```typescript +import type { UmbEntryPointOnInit } from '@umbraco-cms/backoffice/extension-api'; + +const manifests: Array = [ + { + type: '...', + alias: 'my.customization', + name: 'My customization' + ... + }, + ... +]; + +export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { + // Register the extensions + extensionRegistry.registerMany(manifests); +} +``` +{% endcode %} + +## What's next? + +See the Extension Types article for more information about all the different extension types available in Umbraco: + +{% content-ref url="./" %} +[.](./) +{% endcontent-ref %} + +Read about running code before logging in using an `appEntryPoint`: + +{% content-ref url="app-entry-point.md" %} +[app-entry-point.md](app-entry-point.md) +{% endcontent-ref %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/block-custom-view.md b/17/umbraco-cms/customizing/extending-overview/extension-types/block-custom-view.md new file mode 100644 index 00000000000..469cd2746f1 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/block-custom-view.md @@ -0,0 +1,82 @@ +--- +description: Bring your own representation for Blocks. +--- + +# Block Custom View + +The Block Custom View extension type lets you define a Web Component for representing blocks. + +## Build a Custom View + +1. Make a Document Type with a Property using a Block Editor of choice. +2. Configure at least one Block Type on the Block Editor. +3. Ensure the Element Type of the Blocks Content Model has a property using `headline` as the Property Alias. +4. Take note of the Element Type Alias as you will use that in the next step. +5. Add the following code to the `umbraco-package.json` file: + +{% code title="umbraco-package.json" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My.CustomViewPackage", + "version": "0.1.0", + "extensions": [ + { + "type": "blockEditorCustomView", + "alias": "my.blockEditorCustomView.Example", + "name": "My Example Custom View", + "element": "/App_Plugins/welcome-dashboard/dist/example-block-custom-view.js", + "forContentTypeAlias": "{Insert Element Type Alias here}" + } + ] + +``` +{% endcode %} + +The code of your Web Component could look like this: + +{% code title="example-custom-view.ts" %} +```typescript +import { html, customElement, LitElement, property, css } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import type { UmbBlockDataType } from '@umbraco-cms/backoffice/block'; +import type { UmbBlockEditorCustomViewElement } from '@umbraco-cms/backoffice/block-custom-view'; + +@customElement('example-block-custom-view') +export class ExampleBlockCustomView extends UmbElementMixin(LitElement) implements UmbBlockEditorCustomViewElement { + + @property({ attribute: false }) + content?: UmbBlockDataType; + + render() { + return html` +
My Custom View
+

Headline: ${this.content?.headline}

+ `; + } + + static styles = [ + css` + :host { + display: block; + height: 100%; + box-sizing: border-box; + background-color: darkgreen; + color: white; + border-radius: 9px; + padding: 12px; + } + `, + ]; + +} +export default ExampleBlockCustomView; + +declare global { + interface HTMLElementTagNameMap { + 'example-block-custom-view': ExampleBlockCustomView; + } +} + +``` +{% endcode %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/block-editors-custom-view.md b/17/umbraco-cms/customizing/extending-overview/extension-types/block-editors-custom-view.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/bundle.md b/17/umbraco-cms/customizing/extending-overview/extension-types/bundle.md new file mode 100644 index 00000000000..9e913b6e50f --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/bundle.md @@ -0,0 +1,66 @@ +--- +description: Gather Extension Manifests in one file +--- + +# Bundle + +The `bundle` Extension Type points to a single JavaScript file that exports or re-exports Extension Manifests written in JavaScript. + +It can be used as the entry point for a package, or as a grouping for a set of manifests. A Bundle can reference other Bundles. + +## Use Bundle as an entry point for a package + +If you want to declare your manifests in JavaScript/TypeScript, the Bundle is a great choice. + +The following example shows an `umbraco-package.json` that refers to one bundle, which can then declare manifests. + +{% code title="umbraco-package.json" %} +```json + { + "name": "My Package Name", + "version": "1.0.0", + "extensions": [ + { + "type": "bundle", + "alias": "My.Package.Bundle", + "name": "My Package Bundle", + "js": "/App_Plugins/my-package/manifests.js" + } + ] + } +``` +{% endcode %} + +{% code title="manifests.ts" %} +```typescript +export const manifests: Array = [ + { + type: 'dashboard', + name: 'Example Dashboard', + alias: 'example.dashboard.demo', + element: () => import('./demo-dashboard.js'), + weight: 900, + meta: { + label: 'Demo example', + pathname: 'demo-example', + }, + }, + // ... insert as many manifests as you like +] +``` +{% endcode %} + +{% hint style="info" %} +Ensure you have set up your `tsconfig.json` to include the `extension-types` as global types. Like this: + +```json +{ + "compilerOptions": { + ... + "types": [ + "@umbraco-cms/backoffice/extension-types" + ] + } +} +``` +{% endhint %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/collections/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/collections/README.md new file mode 100644 index 00000000000..323c657fb09 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/collections/README.md @@ -0,0 +1,6 @@ +--- +description: >- + An overview of the available extension types related to collections. +--- + +# Extension Types: Collections diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection-action.md b/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection-action.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection-view.md b/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection-view.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection.md b/17/umbraco-cms/customizing/extending-overview/extension-types/collections/collection.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/condition.md b/17/umbraco-cms/customizing/extending-overview/extension-types/condition.md new file mode 100644 index 00000000000..3cfc1668521 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/condition.md @@ -0,0 +1,140 @@ +--- +description: >- + Learn how to declare requirements for your extensions using the Extension + Conditions. +--- + +# Extension Conditions + +Extension Conditions let you define specific requirements that must be met for an extension to be available. While not all Extension Types support Conditions, many do. + +For information on how to utilize conditions in your Manifest, see the [Utilizing Conditions in your Manifest](../extension-conditions.md#utilizing-conditions-in-your-manifest) section. + +## Built-in Conditions Types + +The following conditions are available out of the box, for all extension types that support Conditions. + +* `Umb.Condition.Switch` - Toggles on and off based on the `frequency` set in seconds. +* `Umb.Condition.MultipleAppLanguages` - Requires the app to have more than one language, such as a multi-language site. +* `Umb.Condition.SectionAlias` - Requires the current Section Alias to match the one specified. +* `Umb.Condition.MenuAlias` - Requires the current Menu Alias to match the one specified. +* `Umb.Condition.WorkspaceAlias` - Requires the current Workspace Alias to match the one specified. +* `Umb.Condition.WorkspaceEntityType` - Requires the current workspace to work on the given Entity Type. Examples: 'document', 'block' or 'user'. +* `Umb.Condition.WorkspaceContentTypeAlias` - Requires the current workspace to be based on a Content Type which Alias matches the one specified. +* `Umb.Condition.Workspace.ContentHasProperties` - Requires the Content Type of the current Workspace to have properties. +* `Umb.Condition.WorkspaceHasCollection` - Requires the current Workspace to have a Collection. +* `Umb.Condition.WorkspaceEntityIsNew` - Requires the current Workspace data to be new, not yet persisted on the server. +* `Umb.Condition.EntityIsTrashed` - Requires the current entity to be trashed. +* `Umb.Condition.EntityIsNotTrashed` - Requires the current entity to not be trashed. +* `Umb.Condition.SectionUserPermission` - Requires the current user to have permissions to the given Section Alias. +* `Umb.Condition.UserPermission.Document` - Requires the current user to have specific Document permissions. Example: 'Umb.Document.Save'. +* `Umb.Condition.CurrentUser.GroupId` - Requires the current user to belong to a specific group by GUID. Accepts `match` (GUID), `oneOf` (array), `allOf` (array), and `noneOf` (array). Example: '8d2b3c4d-4f1f-4b1f-8e3d-4a6b7b8c4f1e'. +* `Umb.Condition.CurrentUser.IsAdmin` - Requires the current user to be an admin as defined by the backend, for example, that they belong to the Administrator group. + +## Make your own Conditions + +```html + +``` + +You can make your own Conditions by creating a class that implements the `UmbExtensionCondition` interface. + +```typescript +import { + UmbConditionConfigBase, + UmbConditionControllerArguments, + UmbExtensionCondition +} from '@umbraco-cms/backoffice/extension-api'; +import { UmbConditionBase } from '@umbraco-cms/backoffice/extension-registry'; +import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +export type MyExtensionConditionConfig = UmbConditionConfigBase<'My.Condition.CustomName'> & { + match?: string; +}; + +export class MyExtensionCondition extends UmbConditionBase implements UmbExtensionCondition { + constructor(host: UmbControllerHost, args: UmbConditionControllerArguments) { + super(host, args); + + // enable extension after 10 seconds + setTimeout(() => { + this.permitted = true; + args.onChange(); + }, 10000); + } +} + +// Declare the Condition Configuration Type in the global UmbExtensionConditionConfigMap interface: +declare global { + interface UmbExtensionConditionConfigMap { + MyExtensionConditionConfig: MyExtensionConditionConfig; + } +} +``` + +The global declaration on the last five lines makes your Condition appear valid for manifests using the type `UmbExtensionManifest`. Also, the Condition Config Type alias should match the alias given when registering the condition below. + +The Condition then needs to be registered in the Extension Registry: + +```typescript +export const manifest: UmbExtensionManifest = { + type: 'condition', + name: 'My Condition', + alias: 'My.Condition.CustomName', + api: MyExtensionCondition, +}; +``` + +Finally, you can make use of your condition in any manifests: + +```typescript +export const manifest: UmbExtensionManifest = { + type: 'workspaceAction', + name: 'example-workspace-action', + alias: 'My.Example.WorkspaceAction', + elementName: 'my-workspace-action-element', + conditions: [ + { + alias: 'Umb.Condition.SectionAlias', + match: 'My.Example.Workspace' + }, + { + alias: 'My.Condition.CustomName' + } + ] +} +``` + +As shown in the code above, the configuration property `match` isn't used for our condition. We can do this by replacing the timeout with some other check: + +```typescript +// ... + +export class MyExtensionCondition extends UmbConditionBase implements UmbExtensionCondition { + constructor(host: UmbControllerHost, args: UmbConditionControllerArguments) { + super(host, args); + + if (args.config.match === 'Yes') { + this.permitted = true; + args.onChange(); + } + } +} + +// ... +``` + +With all that in place, the configuration can look like shown below: + +```typescript +{ + // ... + conditions: [ + // ... + { + alias: 'My.Condition.CustomName', + match: 'Yes' + } + ] +} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/current-user-action.md b/17/umbraco-cms/customizing/extending-overview/extension-types/current-user-action.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/dashboard-collection.md b/17/umbraco-cms/customizing/extending-overview/extension-types/dashboard-collection.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/dashboard.md b/17/umbraco-cms/customizing/extending-overview/extension-types/dashboard.md new file mode 100644 index 00000000000..8ce78688c34 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/dashboard.md @@ -0,0 +1,135 @@ +--- +description: A guide to creating custom dashboards in Umbraco +--- + +# Dashboards + +Each section of the Umbraco backoffice has its own set of default dashboards. Your own custom sections can show dashboards, and you can create your own custom dashboards for existing sections. + +
The Getting Started dashboard in Umbraco

The Getting Started dashboard in Umbraco

+ +The dashboard area of Umbraco is used to display an "editor" for the selected item in the tree. If no item is selected, then the default set of section dashboards is shown in the dashboard area. + +Notice that [Section Views](sections/section-view.md) is another similar approach to append information to the root of a Section. Section views are thought mainly to be used as Secondary pages. These two approaches should ideally not be combined. + +## Default Dashboards in Umbraco + +The default dashboards in Umbraco are the ones that are displayed when you first enter a section in the backoffice. These dashboards are used to display information and functionality that is relevant to the section you are in. + +The default sections in Umbraco are: + +| Alias | Name | +| ----------------------- | ---------- | +| Umb.Section.Content | Content | +| Umb.Section.Media | Media | +| Umb.Section.Settings | Settings | +| Umb.Section.Members | Members | +| Umb.Section.Users | Users | +| Umb.Section.Translation | Dictionary | + +Here is a table of the default dashboards in Umbraco and the sections they are used including their aliases: + +| Alias | Section | Weight | Description | +| -------------------------------- | -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| Umb.Dashboard.UmbracoNews | Umb.Section.Content | 20 | The Getting Started dashboard users see when they first enter Umbraco. Contains the latest news of Umbraco including outbound links to resources | +| Umb.Dashboard.RedirectManagement | Umb.Section.Content | 10 | Contains a list of active URL redirects | +| Umb.Dashboard.SettingsWelcome | Umb.Section.Settings | 500 | Contains a set of boxes with links to appropriate resources | + +Even though these dashboards are useful, you might want to create your own custom dashboard to display specific information or functionality. + +You can try and [create a custom dashboard](../../../tutorials/creating-a-custom-dashboard/) as a way on getting started on this topic. + +## Registering your Dashboard + +This section dives into the Dashboard Extension Manifest, shows how to register one, and append additional details. + +### Example Extension Manifest + +{% hint style="info" %} +You can read more about manifests in the tutorial [Creating Your First Extension](../../../tutorials/creating-your-first-extension.md). +{% endhint %} + +Insert this as an entry in the `extensions` list in a `umbraco-package.json` file. + +{% code title="~/App_Plugins/WelcomeDashboard/umbraco-package.json" lineNumbers="true" %} +```json +{ + "type": "dashboard", + "alias": "my.welcome.dashboard", + "name": "My Welcome Dashboard", + "element": "/App_Plugins/WelcomeDashboard/dashboard.js", + "weight": -1, + "meta": { + "label": "Welcome Dashboard", + "pathname": "welcome-dashboard" + } +} +``` +{% endcode %} + +This will register a dashboard with the alias `my.welcome.dashboard` and the name `My Welcome Dashboard`. The dashboard will be loaded from the file `/App_Plugins/WelcomeDashboard/dashboard.js`. The dashboard will be displayed with the label `Welcome Dashboard` and the URL `/welcome-dashboard` on _all sections_, e.g. `/section/content/dashboard/welcome-dashboard`. + +### Conditions + +You can specify conditions for when the dashboard should be displayed. This is done by adding a `conditions` property to the manifest. Ideally, we would like the dashboard to be shown only in a specific section. This can be done by specifying the condition called `Umb.Condition.SectionAlias` and providing the [alias of the section](dashboard.md#default-dashboards-in-umbraco) you want the dashboard to be displayed on: + +```json +"conditions": [ + { + "alias": "Umb.Condition.SectionAlias", + "match": "Umb.Section.Content" + } +] +``` + +This will make the dashboard only be displayed on the Content section. + +{% hint style="info" %} +You can read more about [Extension Conditions](condition.md) in the documentation. +{% endhint %} + +### Properties + +The dashboard manifest can contain the following properties: + +| Property | Type | Description | +| ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| type | string | The type of extension, should be `dashboard` | +| alias | string | A unique alias for the dashboard extension | +| name | string | The name of the dashboard extension | +| element | string | The path to the JavaScript file that exports the dashboard | +| elementName | string | (Optional) The name of the Web Component that contains the dashboard (only if not a default export) | +| weight | number | (Optional) The weight of the dashboard, higher numbers are displayed first | +| meta | object |

Additional metadata for the dashboard

PropertyTypeDescription
LabelstringThe label shown to the user
pathnamestringThe routable URL pathname
| +| Property | Type | Description | +| Label | string | The label shown to the user | +| pathname | string | The routable URL pathname | +| conditions | array | (Optional) [Conditions](condition.md) for when the dashboard should be displayed | + +### Full Example + +{% code title="~/App_Plugins/WelcomeDashboard/umbraco-package.json" lineNumbers="true" %} +```json +{ + "type": "dashboard", + "alias": "my.welcome.dashboard", + "name": "My Welcome Dashboard", + "element": "/App_Plugins/WelcomeDashboard/dashboard.js", + "weight": -1, + "meta": { + "label": "Welcome Dashboard", + "pathname": "welcome-dashboard" + }, + "conditions": [ + { + "alias": "Umb.Condition.SectionAlias", + "match": "Umb.Section.Content" + } + ] +} +``` +{% endcode %} + +
The Welcome Dashboard shown in the Content section

The Welcome Dashboard appears in the Content section

+ +You can learn about [creating a custom dashboard](../../../tutorials/creating-a-custom-dashboard/) in the tutorials section. Here you will learn how to build the dashboard itself as a Web Component. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/dynamic-root-origin.md b/17/umbraco-cms/customizing/extending-overview/extension-types/dynamic-root-origin.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/dynamic-root-query-step.md b/17/umbraco-cms/customizing/extending-overview/extension-types/dynamic-root-query-step.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/entity-actions.md b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-actions.md new file mode 100644 index 00000000000..2554b0a6cac --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-actions.md @@ -0,0 +1,216 @@ +--- +description: Entity Actions perform an action on a specific item +--- + +# Entity Actions + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +{% hint style="info" %} +Entity Actions was previously called Tree Actions. +{% endhint %} + +Entity Actions is a feature that provides a generic place for secondary or additional functionality for an entity type. An entity type can be a media, document and so on. + +Items in an Umbraco Tree can have associated Actions. The actions visible to the currently logged in user can be controlled via User Permissions. + +You can set a User's permissions for each item in the Umbraco Content tree from the User Section of the Umbraco Backoffice. + +If you are developing a custom section or a custom Dashboard, you might want to display some different options. This depends on a User's permission set on a particular item. + +## Entity Actions in the UI + +
+ +

Sidebar Context Menu

+ + + +

Workspace Entity Action Menu

+ +
+ +
+ +

Collection

+ + + +

Pickers

+ +
+ +### Sidebar Context Menu + +Sidebar Context Menu is an entity action that can be performed on a menu item. For example in the content section you can perform some extra actions on the content such as sorting, moving, etc. + +

Default Entity Action in the Content Section

+ +## Registering an Entity Action + +```typescript +import { extensionRegistry } from '@umbraco-cms/extension-registry'; +import { MyEntityAction } from './entity-action'; + +const manifest = { + type: 'entityAction', + alias: 'My.EntityAction', + name: 'My Entity Action', + weight: 10, + api: MyEntityAction, + forEntityTypes: ['my-entity'], + meta: { + icon: 'icon-add', + label: 'My Entity Action', + repositoryAlias: 'My.Repository', + }, +}; + +extensionRegistry.register(manifest); +``` + +**Default Element** + +```typescript +interface UmbEntityActionElement {} +``` + +### The Entity Action Class + +As part of the Extension Manifest you can attach a class that will be instantiated as part of the action. It will have access to the host element, a repository with the given alias and the unique (key etc) of the entity. + +The class either provides a getHref method, or an execute method. If the getHref method is provided, the action will use the link. Otherwise the `execute` method will be used. When the action is clicked the `execute` method on the api class will be run. When the action is completed, an event on the host element will be dispatched to notify any surrounding elements. + +Example of providing a `getHref` method: + +```typescript +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import type { MyRepository } from './my-repository'; + +export class MyEntityAction extends UmbEntityActionBase { + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { + super(host, repositoryAlias, unique); + } + + async getHref() { + return 'my-link/path-to-something'; + } +} +``` + +Example of providing a `execute` method: + +```typescript +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import type { MyRepository } from './my-repository'; + +export class MyEntityAction extends UmbEntityActionBase { + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { + super(host, repositoryAlias, unique); + } + + async execute() { + await this.repository.myAction(this.unique); + } +} +``` + +If any additional contexts are needed, these can be consumed from the host element: + +```typescript +import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; +import { UmbContextConsumerController } from '@umbraco-cms/controller'; +import { UMB_MODAL_SERVICE_CONTEXT } from '@umbraco-cms/modal'; +import { MyRepository } from './my-repository'; + +export class MyEntityAction extends UmbEntityActionBase { + constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { + super(host, repositoryAlias, unique); + + new UmbContextConsumerController(this.host, UMB_MODAL_SERVICE_CONTEXT, (instance) => { + this.#modalService = instance; + }); + } + ... +} +``` + +We currently have a couple of generic actions that can be used across silos, so we don't have to write the same logic again. These actions include copy, move, trash, delete, etc. We can add more as we discover the needs. + +## User Permission Codes + +Here is a list of the entity actions and associated user permission codes shipped by Umbraco CMS and add-on projects, such as Umbraco Deploy. This list also includes codes used by some community packages. + +If you are building a package or adding custom entity actions to your solution, it's important to pick a permission letter. Ensure that it doesn't clash with one of these. + +If you have created a package using a custom entity action, please consider providing an update to this documentation page. You can do this via a PR to the [documentation repository](https://github.com/umbraco/UmbracoDocs). This will allow other developers to discover and avoid using the same permission letter. + +Currently, we allow two extension points on the client for user permissions: + +* **Entity User Permissions** - Relates to an entity (example document). + +

Entity User Permissions UI

+ +* **Granular User Permission** - Relates to a $type server schemaType. + +

Granular User Permission UI

+ +Each permission comes with a set of verbs, that will be checked against client and server-side. + +The Core currently ships with entity user permission for documents. The permissions are as follows: + +| Current Backoffice Letter | Verb | +| ------------------------- | -------------------------------- | +| C | Umb.Document.Create | +| F | Umb.Document.Read | +| A | Umb.Document.Update | +| D | Umb.Document.Delete | +| I | Umb.Document.CreateBlueprint | +| N | Umb.Document.Notifications | +| U | Umb.Document.Publish | +| R | Umb.Document.Permissions | +| Z | Umb.Document.Unpublish | +| O | Umb.Document.Duplicate | +| M | Umb.Document.Move | +| S | Umb.Document.Sort | +| I | Umb.Document.CultureAndHostnames | +| P | Umb.Document.PublicAccess | +| K | Umb.Document.Rollback | +| V | Umb.DocumentRecycleBin.Restore | + +**Entity User Permissions** will be registered in the extension registry with a manifest with the following type. Example: + +```typescript +{ + "type": "entityUserPermission", + "alias": "Umb.UserPermission.Document.Rollback", + "name": "Document Rollback User Permission", + "meta": { + "entityType": "document", + "verbs": ["Umb.Document.Rollback"], + "labelKey": "actions_rollback", + "descriptionKey": "actionDescriptions_rollback", + "group": "administration", + }, + }, +``` + +**Granular permissions** will also be registered. It is possible to provide a custom element to build the needed UX for that type of permission: + +```typescript +{ + "type": "userGranularPermission", + "alias": "Umb.UserGranularPermission.Document", + "name": "Document Granular User Permission", + "element": "element.js", + "meta": { + "schemaType": "DocumentPermissionPresentationModel", + "label": "Documents", + "description": "Assign permissions to specific documents", + }, + }, +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/entity-bulk-actions.md b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-bulk-actions.md new file mode 100644 index 00000000000..797b5aebc15 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-bulk-actions.md @@ -0,0 +1,57 @@ +# Entity Bulk Actions + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +**Entity Bulk Action:** Relates to an entity type: document, media, etc. Performs the action on a selection of items. + +

Entity Bulk Collection

+ +## Registering an Entity Bulk Action + +```typescript +import { extensionRegistry } from '@umbraco-cms/extension-registry'; +import { MyEntityBulkAction } from './entity-bulk-action'; + +const manifest = { + type: 'entityBulkAction', + alias: 'My.EntityBulkAction', + name: 'My Entity Bulk Action', + weight: 10, + api: MyEntityBulkAction, + meta: { + icon: 'icon-add', + label: 'My Entity Bulk Action', + repositoryAlias: 'My.Repository', + }, + conditions: [ + { + alias: 'Umb.Condition.CollectionAlias', + match: 'my-collection-alias', + }, + ], +}; + +extensionRegistry.register(manifest); +``` + +## The Entity Bulk Action Class + +As part of the Extension Manifest you can attach a class that will be instantiated as part of the action. It will have access to the host element, a repository with the given alias and the unique (key etc) of the entity. When the action is clicked the `execute` method on the api class will be run. When the action is completed, an event on the host element will be dispatched to notify any surrounding elements. + +```typescript +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { MyRepository } from './my-repository'; + +export class MyEntityBulkAction extends UmbEntityBulkActionBase { + constructor(host: UmbControllerHostElement, repositoryAlias: string, selection: Array) { + super(host, repositoryAlias, selection); + } + + async execute() { + await this.repository?.myBulkAction(this.selection); + } +} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/entity-create-option-action.md b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-create-option-action.md new file mode 100644 index 00000000000..ec78f6ea732 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/entity-create-option-action.md @@ -0,0 +1,67 @@ +# Entity Create Option Action + +An "Entity Create Option Action" is an additional option that can be added when creating an entity. For example, options like "Create Document Type" or "Create Document Type with Template" can be available when a Document Type is being created. + +These options will be displayed in a create options dialog when the "Create"-entity action is selected. The dialog will show the available options and allow the user to select one of them. + +To enable a "Create"-entity action to show the options dialog, use the 'create'-kind in the manifest when setting up the "Create"-entity action. This will display the options dialog if multiple options are available, or it will automatically execute the first option if only one is available. + +By using the "create"-kind for your create entity actions, you can ensure that your options are extendable by other developers. This also applies when you only have one option available + +The following code shows you to register a "Create"-entity action that can display a dialog with options: + +```typescript +const manifest = { + type: "entityAction", + kind: "create", + alias: "My.EntityAction", + name: "My Create Entity Action", + forEntityTypes: ["my-entity"], +}; +``` + +The following code demonstrates how to register an Entity Create Option Action. If only one option is available, it will be executed immediately. + +```typescript +const manifest = { + type: "entityCreateOptionAction", + alias: "My.EntityCreateOptionAction", + name: "My Create Option Action", + weight: 100, + api: () => import("./path-to-file.js"), + forEntityTypes: ["my-entity"], + meta: { + icon: "icon-unplug", + label: "My Create Option Action", + additionalOptions: false, + }, +}; +``` + +The following code shows how to implement the Create Action Option. + +```typescript +import { + UmbEntityCreateOptionActionBase, + type MetaEntityCreateOptionAction, + type UmbEntityCreateOptionActionArgs, +} from "@umbraco-cms/backoffice/entity-create-option-action"; +import type { UmbControllerHostElement } from "@umbraco-cms/backoffice/controller-api"; + +export class MyEntityCreateActionOption extends UmbEntityCreateOptionActionBase { + constructor( + host: UmbControllerHostElement, + args: UmbEntityCreateOptionActionArgs + ) { + super(host, args); + } + + override async execute() { + alert("My Create Option Action executed!"); + } +} +``` + +We currently support Create Options for the following entity types: + +- User diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/entry-point.md b/17/umbraco-cms/customizing/extending-overview/extension-types/entry-point.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/global-context.md b/17/umbraco-cms/customizing/extending-overview/extension-types/global-context.md new file mode 100644 index 00000000000..744314d195c --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/global-context.md @@ -0,0 +1,24 @@ +--- +description: Establish the bond for extensions to communication across the application +--- + +# Global Context + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A global context manages the logic code from your Lit Element controllers. + +## Registration of a Global Context + +You can register a global context like so: + +```typescript +{ + type: 'globalContext', + alias: 'My.GlobalContext.Products', + name: 'My Products Context', + api: 'my-products.context.js', +} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/granular-user-permissions.md b/17/umbraco-cms/customizing/extending-overview/extension-types/granular-user-permissions.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/header-apps.md b/17/umbraco-cms/customizing/extending-overview/extension-types/header-apps.md new file mode 100644 index 00000000000..bed73e38e45 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/header-apps.md @@ -0,0 +1,149 @@ +--- +description: Place single-purpose extensions in the top-level navigation bar, next to the user profile avatar. +--- + +# Header Apps + +Header App extensions appear next to the user profile and the global search icon in the top right of Umbraco’s Backoffice. Extension authors can create custom header apps to add globally accessible functionality to the Backoffice. + +

Header Apps

+ +## Button Header Apps as a link +Extension authors can create header apps that link to resource both inside and outside the backoffice. Header apps can be created using a manifest or using TypeScript. + +To create a link-style header app, define a `headerApp` extension in the `umbraco-package.json` file. Be sure to include `meta.label` and `meta.icon` so that your header app appears when you reload the backoffice. + +If `meta.href` is defined, the header app will function as a link. Links will open in the same tab. + +Header Apps can also be created using TypeScript. Examples of both approaches are shown below. + +{% tabs %} +{% tab title="Using the Package Manifest" %} +{% code title="umbraco-package.json" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Package", + "version": "0.1.0", + "extensions": [ + { + "type": "headerApp", + "alias": "My.HeaderApp", + "name": "My Header App", + "kind": "button", + "meta": { + "label": "Hello Umbraco", + "icon": "icon-hearts", + "href": "https://umbraco.com/" + } + } + ] +} +``` +{% endcode %} +{% endtab %} +{% tab title="Using TypeScript" %} +{% code title="my-element.ts" %} +Create an object that implements the `UmbExtensionManifest` interface, then register the extension with the `umbExtensionsRegistry` service. + +```typescript +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +const manifest: UmbExtensionManifest = { + type: "headerApp", + alias: "My.HeaderApp.Documentation", + name: "My Documentation Header App", + kind: "button", + meta: { + label: "Hello Documentation", + icon: "icon-addressbook", + href: "https://docs.umbraco.com/" + } +}; + +umbExtensionsRegistry.register(manifest); +``` +{% endcode %} +{% endtab %} +{% endtabs %} + +## Button Header Apps with deeper interactivity + +Extension authors can also create header apps that have more interactivity than a link. + +By creating a custom component, extension authors can control how the button renders itself and how it behaves when clicked. This allows header apps to control navigation, open modals, or perform other actions. + +For example, this is how the current user header app is able to present a modal when clicked. + +

The current user modal is presented from a header app

+ +In order for a header app to have some functionality, extension authors will need to define behavior by creating a JavaScript or TypeScript component. Once the component has been created, it will need to be registered in the header app's `element` property. + +{% tabs %} +{% tab title="Package Manifest" %} +{% code title="umbraco-package.json" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Package", + "version": "0.1.0", + "extensions": [ + { + "type": "headerApp", + "alias": "My.HeaderApp.ServerServices", + "name": "My Server Services Header App", + "kind": "button", + "element": "/App_Plugins/MyPackage/server-services-header-app.js" + } + ] +} +``` +{% endcode %} +{% endtab %} +{% tab title="TypeScript" %} +This example assumes that the extension author has transpiled the above TypeScript code into a JavaScript file. The name and location of the transpiled file should match the `element` property in the package manifest. +{% code title="src/server-services-header.ts" lineNumbers="true" %} +```typescript +import { html, customElement } from "@umbraco-cms/backoffice/external/lit"; +import { UmbHeaderAppButtonElement } from "@umbraco-cms/backoffice/components"; +import { umbOpenModal, UMB_CONFIRM_MODAL } from "@umbraco-cms/backoffice/modal"; + +@customElement("my-server-services-header-app") +export class MyServerServicesHeaderAppElement extends UmbHeaderAppButtonElement { + async #handleUserClick() { + umbOpenModal(this, UMB_CONFIRM_MODAL, { + data: { + headline: "Would you like to disable all Server Services?", + content: + "This action can be undone, but only after all services have stopped.", + color: "danger", + confirmLabel: "Disable all services", + }, + }) + .then(() => { + console.log("User has approved"); + }) + .catch(() => { + console.log("User has rejected"); + }); + } + + override render() { + return html` + + + + `; + } +} + +{ MyServerServicesHeaderAppElement as element }; +``` +{% endcode %} +{% endtab %} +{% endtabs %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/health-check.md b/17/umbraco-cms/customizing/extending-overview/extension-types/health-check.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/icons.md b/17/umbraco-cms/customizing/extending-overview/extension-types/icons.md new file mode 100644 index 00000000000..d9b56b4a5d8 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/icons.md @@ -0,0 +1,64 @@ +--- +description: Create custom icon sets for use across the Umbraco backoffice. +--- + +# Icons + +Umbraco extension authors can create custom icon sets for use across the Umbraco backoffice using an extension type called `icons`. + +## Register a new set of icons + +Icons must be registered in a manifest using the Extension API. The manifest can be added through the `umbraco-package.json` file, as shown below. + +{% code title="umbraco-package.json" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My Package", + "version": "0.1.0", + "extensions": [ + { + "type": "icons", + "alias": "My.Icons.Unicorn", + "name": "My Unicorn Icons", + "js": "/App_Plugins/MyPackage/Icons/icons.js" + } + ] +} +``` +{% endcode %} + +The file set in the `js` field contains the details of your icons. These definitions should resemble the following: + +{% code title="icons.js" %} +```javascript +export default [ + { + name: "my-unicorn", + path: () => import("./icon-unicorn.js"), + }, + { + name: "my-giraffe", + path: () => import("./icon-giraffe.js"), + } +] +``` +{% endcode %} + +Prefix each icon name to avoid collisions with other icons. + +Each icon must define a path, either as a string or a dynamic import as shown above. This file must be a JavaScript file containing a default export of an SVG string. See an example below: + +{% code title="icon-unicorn.js" %} +```javascript +export default ``; +``` +{% endcode %} + +### Using Icons in your UI + +The `umb-icon` element can automatically consume any registered icon. + +```html + +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/kind.md b/17/umbraco-cms/customizing/extending-overview/extension-types/kind.md new file mode 100644 index 00000000000..37bb77f1da4 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/kind.md @@ -0,0 +1,123 @@ +--- +description: A kind extension provides the preset for other extensions to use. +--- + +# Kind + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A Kind is a preset configuration that can be inherited by extensions to ensure consistency and reduce redundancy. It defines a set of default properties or behaviors that extensions can adopt, making it easier to maintain and configure extensions that share similar functionality. + +A Kind is always linked to a specific extension type. Extensions using the same type and referencing a Kind automatically inherit its settings, ensuring uniformity across different extensions. + +## Benefits of Using a Kind + +- Reduces redundancy – Common settings are defined once and reused across extensions. +- Ensures consistency – Extensions using the same Kind follow a standardized structure and behavior. +- Simplifies extension definitions – Extensions inherit predefined properties, reducing manual configuration. + +## Kind Registration + +To register a Kind, use the same method as other extensions. The key properties that define a Kind registration are: + +- `type`: Always set to `kind`. +- `alias`: A unique identifier for the Kind. +- `matchType`: Specifies the extension type that the Kind applies to. +- `matchKind`: Defines the Kind alias, which extensions must reference. +- `manifest`: Contains the preset values that extensions will inherit. + +### Example: Registering a Button Kind for Header Apps + +The following example shows how to register a Button Kind for [**Header Apps**](../extension-types/header-apps.md). This kind provides a preset configuration for a button element that can be reused by other Header App extensions. + +```typescript +const manifest: ManifestKind = { + type: 'kind', + alias: 'Umb.Kind.MyButtonKind', // Unique alias for the Kind + matchType: 'headerApp', // Applies to Header App extensions + matchKind: 'button', // Defines the Kind alias + manifest: { + // Add default properties for the 'button' Kind + elementName: 'umb-header-app-button', + }, +}; +``` + +In this example: + +- `type` is set to 'kind' to register it as a Kind extension. +- `matchType` is 'headerApp', specifying that this Kind is for Header App extensions. +- `matchKind` is 'button', which is the alias of the Kind. +- The `manifest` contains default properties like elementName that extensions using this Kind will inherit. + +## Using the Kind in Other Extensions + +To use the Kind in other extensions, the extension must reference it by setting the `type` and `kind` properties. The extension will automatically inherit the Kind's properties. + +### Example: Header App Extension Using the Button Kind + +```typescript +const manifest = { + type: 'headerApp', // Extension type + kind: 'button', // References the 'button' Kind + name: 'My Header App Example', + alias: 'My.HeaderApp.Example', + meta: { + label: 'My Example', + icon: 'icon-home', + href: '/some/path/to/open/when/clicked', + }, +}; + +extensionRegistry.register(manifest); +``` + +In this example, the Header App extension uses the `kind: 'button'`, meaning it inherits the `elementName` defined in the Button Kind. The extension can still add custom properties (like metadata in this case) to further customize the behavior or appearance. + +## Kind Example + +Here’s an example of how to register and use the Button Kind in a Header App extension: + +```typescript +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; + +const manifest: UmbExtensionManifest = { + type: 'kind', + alias: 'Umb.Kind.MyButtonKind', // Alias for the Kind + matchType: 'headerApp', // Extension type the Kind applies to + matchKind: 'button', // Defines the Kind alias + manifest: { + elementName: 'umb-header-app-button', + }, +}; + +umbExtensionsRegistry.register(manifest); +``` + +This code registers the Button Kind, so other Header App extensions using `type: 'headerApp'` and `kind: 'button'` will inherit the preset `elementName: 'umb-header-app-button'`. + +Now, another Header App extension can be created without defining `elementName`, as it will automatically inherit it from the Kind: + +```typescript +import { extensionRegistry } from '@umbraco-cms/extension-registry'; + +const manifest = { + type: 'headerApp', // Extension type + kind: 'button', // References the 'button' Kind + name: 'My Header App Example', + alias: 'My.HeaderApp.Example', + meta: { + label: 'My Example', + icon: 'icon-home', + href: '/some/path/to/open/when/clicked', + }, +}; + +extensionRegistry.register(manifest); +``` + +By referencing the Kind, the extension inherits shared properties like `elementName`, ensuring consistency and reducing redundancy across extensions. This method also makes it easier to update configurations across multiple extensions. + +By using Kinds, you can create reusable, standardized configurations for extensions, helping to streamline development, ensure consistency, and reduce duplication. Understanding how to register and reference Kinds effectively will enhance the maintainability of your Umbraco extensions. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/localization.md b/17/umbraco-cms/customizing/extending-overview/extension-types/localization.md new file mode 100644 index 00000000000..9efc9ffb4e5 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/localization.md @@ -0,0 +1,83 @@ +--- +description: Learn how to manage and use the Backoffice UI Localization files. +--- + +# Localization + +## Registering Localization + +When registering localizations to a language, you must add a new manifest to the Extension API. The manifest can be added through the `umbraco-package.json` file. + +{% hint style="info" %} +The `umbraco-package.json` file is only registered when placed directly in the `/App_Plugins/` or `/App_Plugins/{YourPackageName}` folder. It will not be recognized in nested subfolders. +{% endhint %} + +Usually, the localization keys are provided through a JavaScript module. In this example, we will use a file named `en.js`: + +{% code title="umbraco-package.json" %} +```json +{ + "name": "MyPackage", + "extensions": [ + { + "type": "localization", + "alias": "MyPackage.Localize.EnUS", + "name": "English", + "meta": { + "culture": "en" + }, + "js": "/App_Plugins/MyPackage/Localization/en.js" + } + ] +} +``` +{% endcode %} + +{% hint style="info" %} +Read more about extensions in the [Package Manifest](../../umbraco-package.md) article. +{% endhint %} + +## The Localization file + +The localization files for the UI are JavaScript modules with a default export containing a key-value structure organized in sections. + +{% code title="en.js" %} +```javascript +export default { + section: { + key1: 'value1', + key2: 'value2', + }, +}; +``` +{% endcode %} + +The sections and keys will be formatted into a map in Umbraco with the format `section_key1` and `section_key2.` These form the unique key they are requested. + +If you do not have many translations, you can also choose to include them directly in the meta-object using the `localizations` property: + +{% code title="umbraco-package.json" %} +```json +{ + "name": "MyPackage", + "extensions": [ + { + "type": "localization", + "alias": "MyPackage.Localize.EnUS", + "name": "English", + "meta": { + "culture": "en", + "localizations": { + "section": { + "key1": "value1", + "key2": "value2" + } + } + }, + } + ] +} +``` +{% endcode %} + +In this case, the `en.js` file is not required and we can remove the "js" property from the manifest. Only strings can be used in the meta-object. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/menu-item.md b/17/umbraco-cms/customizing/extending-overview/extension-types/menu-item.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/menu.md b/17/umbraco-cms/customizing/extending-overview/extension-types/menu.md new file mode 100644 index 00000000000..e305a7b8155 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/menu.md @@ -0,0 +1,263 @@ +# Menu + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +

Menu

+ +## Creating a custom menu + +In this section, you can learn how to register and create a custom Menu for the Umbraco backoffice. + +### Manifest + +The manifest file can be created using either JSON or TypeScript. Both methods are shown below. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json +{ + "type": "menu", + "alias": "My.Menu", + "name": "My Menu" +} +``` +{% endtab %} + +{% tab title="TypeScript" %} + +The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests. + +```typescript +import type { ManifestMenu } from '@umbraco-cms/backoffice/menu'; + +const menuManifest: Array = [ + { + type: 'menu', + alias: 'My.Menu', + name: 'My Menu' + } +]; +``` + +{% endtab %} + +{% endtabs %} + +# Menu Item + +

Menu Item

+ +Menu items are the items that appear in the menu. + +## Creating a custom menu items + +In this section, you can learn how to add custom Menu Items to your Umbraco backoffice Menu. + +### Manifest + +To add custom menu items, you can define a single MenuItem manifest and link an element to it. In this element, you can fetch the data and render as many menu items as you want based on that data. + +The code snippets below show how to declare a new menu item using JSON or TypeScript. + +{% tabs %} + +{% tab title="JSON" %} + +We can create the manifest using JSON in the `umbraco-package.json`. + +```json +{ + "type": "menuItem", + "alias": "My.MenuItem", + "name": "My Menu Item", + "element": "./menu-items.ts", + "meta": { + "label": "My Menu Item", + "menus": ["My.Menu"] + } +} +``` + +{% endtab %} + +{% tab title="TypeScript" %} + +The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests. + +{% code title="manifest.ts" overflow="wrap" lineNumbers="true" %} +```typescript +const menuItemManifest: Array = [ + { + type: 'menuItem', + alias: 'My.MenuItem', + name: 'My Menu Item', + meta: { + label: 'My Menu Item', + menus: ["My.Menu"] + }, + element: () => import('./menu-items.ts') + } +]; +``` +{% endcode %} + + +{% endtab %} + +{% endtabs %} + +### The UI Element + +#### Rendering menu items with Umbraco's UI menu item component + +To render your menu items in Umbraco, you can use the [Umbraco UI Menu Item component](https://uui.umbraco.com/?path=/docs/uui-menu-item--docs). This component allows you to create nested menu structures with a few lines of code. + +By default, you can set the `has-children` attribute to display the caret icon indicating nested items. It will look like this: `?has-children=${bool}`. + +**Example:** + +```tsx + + + + +``` + +#### Custom menu item element example + +You can fetch the data and render the menu items using the Lit element above. By putting the result of the fetch in a `@state()`, we can trigger a re-render of the component when the data is fetched. + +{% code title="menu-items.ts" overflow="wrap" lineNumbers="true" %} +```typescript +import type { UmbMenuItemElement } from '@umbraco-cms/backoffice/menu'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { html, TemplateResult, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { MyMenuItemResponseModel, MyMenuResource } from '../../../api'; + +const elementName = 'my-menu-item'; + +@customElement(elementName) +class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { + @state() + private _items: MyMenuItemResponseModel[] = []; // Store fetched items + + @state() + private _loading: boolean = true; // Track loading state + + @state() + private _error: string | null = null; // Track any errors + + override firstUpdated() { + this.fetchInitialItems(); // Start fetching on component load + } + + // Fetch initial items + async fetchInitialItems() { + try { + this._loading = true; + this._items = ((await MyMenuResource.getMenuApiV1()).items); // Fetch root-level items + } catch (e) { + this._error = 'Error fetching items'; + } finally { + this._loading = false; + } + } + + // Render items + renderItems(items: MyMenuItemResponseModel[]): TemplateResult { + return html` + ${items.map(element => html` + + ${element.type === 1 + ? html`` + : html``} + + ${element.hasChildren ? this.renderItems(element.children) : ''} + + `)} + `; + } + + // Main render function + override render() { + if (this._loading) { + return html``; + } + + if (this._error) { + return html` + `; + } + + // Render items if loading is done and no error occurred + return this.renderItems(this._items); + } +} + +export { MyMenuItems as element }; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyMenuItems; + } +} + +``` +{% endcode %} + + +## Tree Menu Item + +### Manifest + +```json +// it will be something like this +{ + "type": "menuItem", + "kind": "tree", + "alias": "My.TreeMenuItem", + "name": "My Tree Menu Item", + "meta": { + "label": "My Tree Menu Item", + "menus": ["My.Menu"] + } +} +``` + +#### Default Element + +The default element supports rendering a subtree of menu items. + +```typescript +class UmbMenuItemTreeDefaultElement {} +``` + +### Adding menu items to an existing menu + +The backoffice comes with a couple of menus. + +* Content, Media, Settings, Templating, Dictionary, etc. + +To add a menu item to an existing menu, you can use the `meta.menus` property. + +```typescript +{ + "type": "menuItem", + "alias": "My.MenuItem", + "name": "My Menu Item", + "meta": { + "label": "My Menu Item", + "menus": ["Umb.Menu.Content"] + } +} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/mfa-login-provider.md b/17/umbraco-cms/customizing/extending-overview/extension-types/mfa-login-provider.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/modals/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/README.md new file mode 100644 index 00000000000..7dc909197de --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/README.md @@ -0,0 +1,106 @@ +--- +description: >- + A modal is a popup layer that darkens the surroundings and comes with a focus + lock. There are two types of modals: "dialog" and "sidebar". +--- + +# Modals + +## **Modal Types** + +The Dialog modal appears in the middle of the screen, and the Sidebar Modal slides in from the right. + +## Open a Modal + +A modal can be opened in two ways: either directly at runtime or by registering a route for the modal. Registering a route allows deep-linking to the modal, which may be preferred in certain scenarios. Otherwise, opening the modal directly is a simpler option. + +### Directly open via the Open Modal method + +
import { customElement, html } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; 
+import { MY_MODAL_TOKEN } from './my-modal.token.js';
+import { umbOpenModal } from '@umbraco-cms/backoffice/modal';
+
+@customElement('my-element')
+class MyElement extends UmbLitElement {
+
+    override render() {
+        return html`
+            <uui-button look="primary" label="Open modal" @click=${this._openModal}></uui-button>
+        `;
+    }
+
+    private async _openModal() {
+        const returnedValue = await umbOpenModal(this, MY_MODAL_TOKEN, {
+            data: {
+                headline: "My modal headline",
+            },
+        }).catch(() => undefined);
+    }
+}
+
+declare global {
+    interface HTMLElementTagNameMap {
+        'my-element': MyElement;
+    }
+}
+
+ +The Promise returned by `umbOpenModal` is handled for potential rejection. This occurs when the Model is closed without submitting. Use this behavior to carry out a certain action if the modal is cancelled. In this case, `undefined` is returned when the Modal is cancelled (rejected). + +See the [Confirm Modal article](confirm-dialog.md) for an example. + +### Directly open via the Modal Manager Context + +For full control, open a modal via the **Modal Manager Context.** This is what the Open Modal method uses behind the scenes. Using the context directly gives you a bit more control and understanding of the system. + +First, consume the `UMB_MODAL_MANAGER_CONTEXT` , then use the modal manager context to open a modal. The following example shows how to consume the Modal Manager Context: + +```ts +import { LitElement } from "@umbraco-cms/backoffice/external/lit"; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import { + UMB_MODAL_MANAGER_CONTEXT, +} from "@umbraco-cms/backoffice/modal"; + +export class MyElement extends UmbElementMixin(LitElement) { + #modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; + + constructor() { + super(); + this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { + this.#modalManagerContext = instance; + // modalManagerContext is now ready to be used. + }); + } +} +``` + +In this case, the modal token from the previous example is used. It accepts a key as input data and returns the new key if the modal is submitted. + +```typescript +const modalContext = this.#modalManagerContext?.open(this, MY_SOMETHING_PICKER_MODAL, { + value: { + key: this.selectedKey, + }, +}); + +modalContext + ?.onSubmit() + .then((value) => { + this.selectedKey = value.key; + }) + .catch(() => undefined); +``` + +[See the implementing a Confirm Dialog for an example.](confirm-dialog.md) + +### Modal Route Registration + +You can register modals with a route, making it possible to link directly to that specific modal. This also means the user can navigate back and forth in the browser history. This makes it an ideal solution for modals containing an editorial experience. + +For a more concrete example, check out the [Modal Route Registration article](route-registration.md). + +## Make a custom Modal + +To create your modal, read the [Implementing a Custom Modal article](custom-modals.md). diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/modals/confirm-dialog.md b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/confirm-dialog.md new file mode 100644 index 00000000000..0ed4ec5b203 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/confirm-dialog.md @@ -0,0 +1,64 @@ +--- +description: Present a dialog to ask the user for confirmation. +--- + +# Confirm Dialog + +Confirmation dialogs are used to ask the user for confirmation to complete some action and are presented as a center-aligned modal in the backoffice. + +Extension authors do not need to register the dialog in their extension's manifest, instead these dialogs are opened by importing and calling the `umbOpenModal` function. + +Extension authors can customize the dialog with configuration options such as headline, body content, colors, and button labels. + +* `headline` - The headline of the modal. +* `content` - The content of the modal, which can be a TemplateResult or a string. +* `color` - (Optional) The color of the modal, can be `positive` or `danger`. Defaults to `positive`. +* `confirmLabel` - (Optional) The label of the confirmation button. +* `cancelLabel` - (Optional) The label of the cancel button. + +To see all properties of the `UMB_CONFIRM_MODAL` token, see the [API reference](https://apidocs.umbraco.com/v16/ui-api/interfaces/packages_core_modal.UmbConfirmModalData.html). + +The `onSubmit` method returns a promise that resolves when the user confirms the dialog, and rejects when the user cancels the dialog. + +## Basic Usage + +{% code title="my-element.ts" %} +```typescript +import { + html, + LitElement, + customElement, +} from "@umbraco-cms/backoffice/external/lit"; +import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; +import { umbOpenModal, UMB_CONFIRM_MODAL } from "@umbraco-cms/backoffice/modal"; + +@customElement("my-confirmation-modal") +export class MyConfirmationModal extends UmbElementMixin(LitElement) { + #onRequestDisable() { + umbOpenModal(this, UMB_CONFIRM_MODAL, { + data: { + headline: this.localize.term("actions_disable"), + content: this.localize.term("defaultdialogs_confirmdisable"), + color: "danger", + confirmLabel: this.localize.term("actions_disable"), + }, + }) + .then(() => { + console.log("User has approved"); + }) + .catch(() => { + console.log("User has rejected"); + }); + } + + render() { + return html``; + } +} +``` +{% endcode %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md new file mode 100644 index 00000000000..7cdba526405 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md @@ -0,0 +1,147 @@ +--- +description: New modals can be added to the system via the extension registry. +--- + +# Custom Modals + +This article goes through adding new modals to the system. There are three steps to creating a custom modal: + +* Create a modal element +* Declare an Extension Manifest +* (Optional) Create a Modal Token + +After completing these steps, refer to the example on how to open the modal. + +## Create a modal element + +A modal element is a web component that is used to render a modal. It should implement the `UmbModalExtensionElement` interface. The modal context is injected into the element when the modal is opened in the `modalContext` property. The modal context is used to close the modal, update the value and submit the modal. + +Additionally, the modal element can see its data parameters through the `modalContext` property. In this example, the modal data is of type `MyModalData` , and the modal value is of type `MyModalValue`. The modal context is of type `UmbModalContext`. We are using the data to render a headline and the value to update the value and submit the modal. + +{% code title="my-modal.element.ts" %} +```ts +import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbModalExtensionElement } from '@umbraco-cms/backoffice/modal'; +import type { UmbModalContext } from '@umbraco-cms/backoffice/modal'; +import type { MyModalData, MyModalValue } from './my-modal.token.js'; + +@customElement('my-dialog') +export class MyDialogElement + extends UmbLitElement + implements UmbModalExtensionElement { + + @property({ attribute: false }) + modalContext?: UmbModalContext; + + @property({ attribute: false }) + data?: MyModalData; + + private _handleCancel() { + this.modalContext?.submit(); + } + + private _handleSubmit() { + this.modalContext?.updateValue({ myData: 'hello world' }); + this.modalContext?.submit(); + } + + render() { + return html` +
+

${this.modalContext?.data.headline ?? 'Default headline'}

+ + +
+ `; + } +} + +export const element = MyDialogElement; +``` +{% endcode %} + +The class must be exported as an `element` or `default` for the Extension Registry to be able to pick up the class. + +## Declare an Extension Manifest + +The modal element needs to be registered in the extension registry. This is done by defining the modal in the manifest file. The `element` property should point to the file that contains the modal element. + +```typescript +{ + type: 'modal', + alias: 'My.Modal', + name: 'My Modal', + element: '../path/to/my-modal.element.js' +} +``` + +## Create a modal token + +{% hint style="info" %} +For type safety, it's recommended to use Modal Tokens. Using a Modal Token gives knowledge about the data that can be parsed to the Modal and as well as the type of the value coming back when submitted. +{% endhint %} + +A Modal Token works as a constant that identifies the modal. It is used to open the modal and knows the types of the modal data and modal value. As well, it can contain a preset, containing default data and modal options. + +The first argument passed to `UmbModalToken` is the extension alias; the second is the preset configuration. + +```ts +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; + +export type MyModalData = { + headline: string; +} + +export type MyModalValue = { + myData: string; +} + +export const MY_MODAL_TOKEN = new UmbModalToken('My.Modal', { + modal: { + type: 'sidebar', + size: 'small' + } +}); +``` + +A modal token is a generic type that takes two arguments(``): + +* The first defines the type of data passed to the modal when opened. +* The second defines the type of value returned when the modal is submitted. + +## Open the modal + +To open the modal, call the `umbOpenModal` method with the Modal Token and data of choice: + +
import { customElement, html } from '@umbraco-cms/backoffice/external/lit';
+import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; 
+import { MY_MODAL_TOKEN } from './my-modal.token.js';
+import { umbOpenModal } from '@umbraco-cms/backoffice/modal';
+
+@customElement('my-element')
+class MyElement extends UmbLitElement {
+
+    override render() {
+        return html`
+            <uui-button look="primary" label="Open modal" @click=${this._openModal}></uui-button>
+        `;
+    }
+
+    private async _openModal() {
+        const returnedValue = await umbOpenModal(this, MY_MODAL_TOKEN, {
+            data: {
+                headline: "My modal headline",
+            },
+        }).catch(() => undefined);
+    }
+}
+
+declare global {
+    interface HTMLElementTagNameMap {
+        'my-element': MyElement;
+    }
+}
+
+ +The Promise of `umbOpenModal` is caught if it gets rejected. This is because if the Model gets closed without submission, the Promise is rejected. YThis can be used to carry out a certain action if the modal is cancelled. In this case, `undefined` is returned when the Modal is cancelled (rejected). diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/modals/route-registration.md b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/route-registration.md new file mode 100644 index 00000000000..f8a0f21f0b5 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/modals/route-registration.md @@ -0,0 +1,127 @@ +--- +description: >- + You can register modals with a route, making it possible to link directly to + that specific modal. This also means the user can navigate back and forth in + the browser history +--- + +# Modal Route Registration + +A modal can be registered via the `UmbModalRouteRegistrationController`. The registration accepts a modal token (or extension alias). + +```ts +this.myModalRegistration = new UmbModalRouteRegistrationController( + this, + UMB_LINK_PICKER_MODAL +) + .onSubmit((submitData) => { + console.log("Modal submitted with data".submitData); + }) + .observeRouteBuilder((routeBuilder) => { + this._modalRouteBuilder = routeBuilder; + }); +``` + +The registration holds an instance of its `UmbModalHandler` when the modal is active. The modal registration accepts 4 different callbacks: + +* `onSetup` - called when the modal is opened +* `onSubmit` - called when the modal is submitted +* `onReject` - called when the modal is rejected +* `observeRouteBuilder` - called when the modal route changes. Use the given route builder to build a route to open the modal + +**Additional features of the route Registration:** + +* Adds unique parts to the path. +* A modal registered in a dashboard can be setup in few steps +* A modal registered in a property editor needs to become specific for the property and the variant of that property. +* Builds some data for the setup. +* Rejects a modal by returning false in setup. +* Uses a parameter as part of the setup to determine the data going to the modal. + +## Modal registration for UI as part of a Property Editor + +When configuring a routed modal from a Property Editor, it's important to be aware of some facts. Those facts are that the Property Editor shares the same URL path as other Property Editors. This means we need to ensure the registration is unique so it doesn't collide with other Property Editors. To do so we will make use of the Property Alias and the Variant ID. + +```ts + + + @property() + public set alias(value: string | undefined) { + this.myModalRegistration.setUniquePathValue('propertyAlias', value); + } + + @property() + public set variantId(value: string | UmbVariantId | undefined) { + this.myModalRegistration.setUniquePathValue('variantId', value?.toString()); + } + + private _items = [ + { name: 'Item 1' }, + { name: 'Item 2' }, + { name: 'Item 3' }, + ] + + + constructor() { + super(); + + this.myModalRegistration = new UmbModalRouteRegistrationController( + this, + MY_MODAL_TOKEN + ) + .addAdditionalPath(`:index`) + .addUniquePaths(['propertyAlias', 'variantId']) + .onSetup((params) => { + // Get item index: + const indexParam = params.index; + if (!indexParam) return false; + let index: number | null = parseInt(params.index); + if (Number.isNaN(index)) return false; + + // Use the index to find data: + let data = null; + if (index >= 0 && index < this._items.length) { + data = this._items[index]; + } else { + // If not then make a new pick: + index = null; + } + + return { + index: index, + itemData: { + name: data?.name + }, + }; + }) + .onSubmit((submitData) => { + if (!submitData) return; + this._items[submitData.index] = submitData.itemData; + }) + .observeRouteBuilder((routeBuilder) => { + this._modalRouteBuilder = routeBuilder; + }); + } + + render() { + return html` + ${this._items?.map((item, index) => + html`Add` + )} + `; + } +``` + +**Generate the URL to a Modal Route Registration** + +The Modal registration has an option to retrieve a URL Builder. This is a function that can be used to generate a URL to a modal: + +```ts +const modalLink = _myUrlBuilder?.({ alias: "my-input-alias" }); +``` + +The `modalLink` from above could look like this: `/umbraco/backoffice/my/location/modal/Our.Modal.SomethingPicker/my-input-alias` + +Notice the Property Editor registration will add the property alias and variant ID to the URL, so it becomes: + +`/umbraco/backoffice/my/location/modal/Our.Modal.SomethingPicker/my-property-alias/en-us/my-input-alias` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/monaco-markdown-editor-action.md b/17/umbraco-cms/customizing/extending-overview/extension-types/monaco-markdown-editor-action.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/package-view.md b/17/umbraco-cms/customizing/extending-overview/extension-types/package-view.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/preview-app-provider.md b/17/umbraco-cms/customizing/extending-overview/extension-types/preview-app-provider.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/property-action.md b/17/umbraco-cms/customizing/extending-overview/extension-types/property-action.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/property-editor-schema.md b/17/umbraco-cms/customizing/extending-overview/extension-types/property-editor-schema.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/property-editor-ui.md b/17/umbraco-cms/customizing/extending-overview/extension-types/property-editor-ui.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/property-value-preset.md b/17/umbraco-cms/customizing/extending-overview/extension-types/property-value-preset.md new file mode 100644 index 00000000000..f2df225b094 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/property-value-preset.md @@ -0,0 +1,88 @@ +--- +description: Provide a preset value for a Property. +--- + +# Property Value Preset + +The Property Value Preset is an Extension Type that uses an API to provide a Preset Value. The preset value is used when a user scaffolds a new set of Content. + +The following Manifest declares a preset for the `Umb.PropertyEditorUi.TextBox` Property Editor UI: + +```typescript +export const manifest = { + type: 'propertyValuePreset', + alias: 'my.propertyValuePreset.TextBox', + name: 'My Property Value Preset for TextBox', + api: () => import('./my-property-value-preset.js'), + forPropertyEditorUiAlias: 'Umb.PropertyEditorUi.TextBox' +} +``` + +Such Property Preset Value API could look like this: + +{% code title="my-property-value-preset.js" %} +```typescript +export class MyPropertyValuePresetApi implements UmbPropertyValuePreset { + async processValue(value: undefined | string, config: UmbPropertyEditorConfig) { + return value ? value : 'Hello there'; + } + + destroy(): void {} +} + +export { UmbTrueFalsePropertyValuePreset as api }; +``` +{% endcode %} + +This API will set the value to "Hello there" for all properties using the `Umb.PropertyEditorUi.TextBox` Property Editor UI. + +### Target a Property Editor Schema + +You can also choose to target your Preset for a Property Editor Schema. + +Define `forPropertyEditorSchemaAlias` to show the Preset Value for all Properties based on that Schema. + +If both `forPropertyEditorSchemaAlias` and `forPropertyEditorUiAlias` are defined, it will not limit the target. The matching is independently for each of them. + +Notice that `forPropertyEditorSchemaAlias` only targets the Properties used on the Content Type based data. This could affect Documents, Media, Members, and Blocks, and not properties of a Data Type Configuration. + +## Utilize the Data-Type configuration + +The `processValue` method takes four arguments: +- The current value. +- The Data Type configuration. +- The type arguments, which contains details such as whether the property is mandatory, and how it varies by culture and segment. +- The call arguments, which contains details about the property and document. + +The following example is the built-in Property Value Preset for the Umbraco Toggle. The Toggle Data Type has a 'preset state' configuration that is used as the value of the Toggle. + +{% code title="my-property-value-preset.js" %} +```typescript +export class UmbTrueFalsePropertyValuePreset + implements UmbPropertyValuePreset +{ + async processValue(value: undefined | UmbTogglePropertyEditorUiValue, config: UmbPropertyEditorConfig, typeArgs: UmbPropertyTypePresetModelTypeModel, callArgs: UmbPropertyValuePresetApiCallArgs) { + const initialState = (config.find((x) => x.alias === 'presetState')?.value as boolean | undefined) ?? false; + return value !== undefined ? value : initialState; + } + + destroy(): void {} +} + +export { UmbTrueFalsePropertyValuePreset as api }; +``` +{% endcode %} + +## Utilize anything + +The `processValue` method is async. You can request the server or use the Context-API to retrieve the necessary information to construct your value. + +It is recommended to use the `getContext` method for retrieving contexts. The method includes a timeout feature that prevents the preset from getting stuck if the context is unavailable during reset. + +## Extend Presets + +Because the `processValue` method takes a value as its first argument, you can append the value constructed by other Presets. In this way, multiple Presets can shape the preset value for a property. + +In the case of multiple Property Value Presets targeting the same Property. The `weight` of the Manifest determines the order they are executed. + +This opens up for you to overwrite or alter the Preset Value for Properties that use a Built-in Property Value Preset. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/search-provider.md b/17/umbraco-cms/customizing/extending-overview/extension-types/search-provider.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/search-result-item.md b/17/umbraco-cms/customizing/extending-overview/extension-types/search-result-item.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/sections/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/README.md new file mode 100644 index 00000000000..498954cfad1 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/README.md @@ -0,0 +1,6 @@ +--- +description: >- + A comprehensive summary of the available extension types associated with sections. +--- + +# Extension Types: Sections diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-route.md b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-route.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-sidebar.md b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-sidebar.md new file mode 100644 index 00000000000..98affff72c5 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-sidebar.md @@ -0,0 +1,158 @@ +--- +description: >- + Use Section Sidebar extensions to add navigation, coordinate Section Views, and provide additional functionality inside Section extensions. +--- + +# Section Sidebar + +[Section extensions](./section.md) can add a Section Sidebar to add navigation, coordinate subviews such as +[Section View extensions](./section-view.md), and provide Section-wide functionality. + +Section Sidebar extensions are optional; if not defined, the Section extension defaults to a single full-screen subview. + +

Section Sidebar

+ +## Section Sidebar Apps + +Section Sidebar extensions can be composed of **one or more** section sidebar apps. Extension authors can include common Umbraco types, such as menus and trees, or create custom sidebar apps using web components. + +

Section Sidebar Apps

+ +### Custom Sidebar App Example + +Section Sidebar extension authors can place any custom web component into the sidebar. Extension authors will need to +supply the `element` property with the path of their custom web component. Specify the full path, starting from the +Umbraco project root. + +Sidebar Section extension authors may specify where the Section Sidebar app appears using +[extension conditions](../condition.md). + +{% code title="umbraco-package.json" %} +```json +{ + "type": "sectionSidebarApp", + "alias": "My.SectionSidebarApp", + "name": "My Section Sidebar App", + "element": "/App_Plugins//sidebar-app.js", + "conditions": [{ + "alias": "Umb.Condition.SectionAlias", + "match": "My.Section" + }] +} +``` +{% endcode %} + +### Menu Sidebar App Examples + +The menu sidebar app, provided by Umbraco, can be placed in Section Sidebar extensions. It attaches to a menu defined in your manifest via the `meta:menu` property, where this value must match the `alias` value of the menu. + +

Menu Sidebar App

+ +{% code title="umbraco-package.json" %} +```json +{ + "type": "sectionSidebarApp", + "kind": "menu", + "alias": "My.SectionSidebarApp.MyMenu", + "name": "My Menu Section Sidebar App", + "meta": { + "label": "My Sidebar Menu", + "menu": "My.Menu" + }, + "conditions": [{ + "alias": "Umb.Condition.SectionAlias", + "match": "My.Section" + }] +} +``` +{% endcode %} + +In the example below, a menu extension is created and bound to the `meta:menu` (My.Menu) property, which matches the menu extension’s `alias`. The _My.Menu_ alias is also used to attach a menu item extension. + +{% code title="umbraco-package.json" %} +```json +[ + { + "type": "menu", + "alias": "My.Menu", + "name": "Section Sidebar Menu" + }, + { + "type": "menuItem", + "alias": "SectionSidebar.MenuItem1", + "name": "Menu Item 1", + "meta": { + "label": "Menu Item 1", + "menus": ["My.Menu"] + } + } +] +``` +{% endcode %} + +For more information, see the documentation for the [menus](../menu.md) extension. + +#### Coordinating subviews with menu items + +Menu sidebar apps can coordinate navigation between subviews in the section extension by referencing +[workspace extensions](../workspaces/workspace.md). Modify the menu item extension to include the `meta:entityType` +property, and assign it the same value as a workspace view extensions' own `meta:entityType` property. + +{% code title="umbraco-package.json" %} +```json +[ + { + "type": "menuItem", + "alias": "SectionSidebar.MenuItem1", + "name": "Menu Item 1", + "meta": { + "label": "Menu Item 1", + "menus": ["My.Menu"], + "entityType": "myCustomWorkspaceView" + } + }, + { + "type": "workspace", + "name": "Workspace 1", + "alias": "SectionSidebar.Workspace1", + "element": "/App_Plugins//my-custom-workspace.js", + "meta": { + "entityType": "myCustomWorkspaceView" + } + } +] +``` +{% endcode %} + +#### Adding items to an existing menu + +Authors can add their extensions to the sidebar of any Umbraco-provided section (Content, Media, Settings, etc.) by configuring `conditions` with the `SectionAlias` property. + +

Composed sidebar menu

+ +{% code title="umbraco-package.json" %} +```json +{ + "type": "sectionSidebarApp", + "alias": "My.SectionSidebarApp", + "name": "My Section Sidebar App", + "element": "/App_Plugins//sidebar-app.js", + "conditions": [{ + "alias": "Umb.Condition.SectionAlias", + "match": "Umb.Section.Settings" + }] +} +``` +{% endcode %} + +Common Umbraco-provided section aliases: + +| Section Aliases | +|-------------------------| +| Umb.Section.Content | +| Umb.Section.Media | +| Umb.Section.Settings | +| Umb.Section.Packages | +| Umb.Section.Users | +| Umb.Section.Members | +| Umb.Section.Translation | diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md new file mode 100644 index 00000000000..ffcdfe16887 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md @@ -0,0 +1,221 @@ +--- +description: >- + Add auxiliary views to your own Umbraco packages, or to other areas of the Umbraco backoffice. +--- + +# Section View + +Section View extensions are containers for custom Umbraco packages or other backoffice areas, including Content, Media, Settings, Users, Members, or Translations. These extensions can contain other Umbraco extensions, like dashboards or web components, enabling package authors to populate the section with any content or custom interface. + +

Section View

+ +## Creating a custom Section View + +Custom Section View extensions are straightforward to create. Extension authors register the Section View extension and +subsequently implement the content or interface they desire to display within the Section View. + +### Registering Section View extensions + +Extension authors can register Section View extensions using two methods: + +- Declarative registration via manifests or +- Imperative registration using TypeScript and [Backoffice Entry Points](../backoffice-entry-point.md). + +Both methods are shown below. + +#### Registering by manifest + +{% tabs %} +{% tab title="Json" %} +Extensions authors can register the Section View extension using a JSON declaration in the `umbraco-package.json` file. + +{% code title="umbraco-package.json" %} +```json +{ + "type": "sectionView", + "alias": "My.SectionView", + "name": "My Section View", + "element": "/App_Plugins//my-section.element.js", + "meta": { + "label": "My View", + "icon": "icon-add", + "pathname": "my-view" + }, + "conditions": [ + { + "alias": "Umb.Condition.SectionAlias", + "match": "My.Section" + } + ] +} +``` +{% endcode %} + +Tip: Use the absolute path, starting from the root of your Umbraco project, in the `element` property for +JSON declarations. TypeScript declarations are capable of employing relative paths. + +{% endtab %} + +{% tab title="TypeScript" %} +The manifest can also be written in TypeScript. + +For this TypeScript example we used a [Backoffice Entry Point](../backoffice-entry-point.md) extension to register the manifests. + +{% code title="my-section.element.ts" %} +```typescript +import type { ManifestSectionView } from '@umbraco-cms/backoffice/section'; + +const sectionViews: Array = [ + { + type: "sectionView", + alias: "My.SectionView", + name: "My Section View", + element: () => import('./my-section.element.ts'), + meta: { + label: "My View", + icon: "icon-add", + pathname: "my-view", + }, + conditions: [ + { + alias: 'Umb.Condition.SectionAlias', + match: 'My.Section', + } + ] + } +] +``` +{% endcode %} + +{% endtab %} +{% endtabs %} + +### Lit Element + +Creating the Section View Element using a Lit Element. + +{% code title="my-section.element.ts" %} +```typescript +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; + +@customElement('my-sectionview-element') +export class MySectionViewElement extends UmbLitElement { + + override render() { + return html` + + Sectionview content goes here + + ` + } + + static override readonly styles = [ + css` + :host { + display: block; + padding: 20px; + } + `, + ]; + +} + +export default MySectionViewElement; + +declare global { + interface HTMLElementTagNameMap { + 'my-sectionview-element': MySectionViewElement; + } +} +``` +{% endcode %} + +## Adding Section Views to your own package + +When developing a Section View extension for their own package, an extension author must create a Section extension to +host the Section View extension. + +Guidelines on creating Section extensions can be found at [this link](./section.md). + +To link a Section View with a Section, set the `match` property in the condition to the same value as the Section's `alias`. In the +provided example, this value is `NetworkServices.Section`. + +{% code title="umbraco-package.json" %} +```json +[ + { + "type": "section", + "alias": "NetworkServices.Section", + "name": "Network Services", + "meta": { + "label": "Network Services", + "pathname": "network-services" + } + }, + { + "type": "sectionView", + "alias": "NetworkServices.Section.Overview", + "name": "Network Services Overview", + "element": "/App_Plugins/NetworkServices/overview-dashboard.js", + "meta": { + "label": "Overview", + "icon": "icon-add", + "pathname": "overview" + }, + "conditions": [ + { + "alias": "Umb.Condition.SectionAlias", + "match": "NetworkServices.Section" + } + ] + } +] +``` +{% endcode %} + +## Adding Section Views to somewhere else in the backoffice + +The Umbraco backoffice architecture places a strong emphasis on composing. Authors can extend existing sections, including core ones like Content, Media, and Settings, with Section View extensions. + +After an author has completed their Section View extension, they can control the placement of the extension using +conditions in the manifest definition. + +The `match` property demonstrates how an extension author can incorporate a custom Section View within the Content +section. + +{% code title="umbraco-package.json" %} +```json +{ + "type": "sectionView", + "alias": "My.SectionView", + "name": "My Section View", + "element": "/App_Plugins//my-section.element.js", + "meta": { + "label": "My View", + "icon": "icon-add", + "pathname": "my-view" + }, + "conditions": [ + { + "alias": "Umb.Condition.SectionAlias", + "match": "Umb.Section.Content" + } + ] +} +``` +{% endcode %} + +Common Umbraco-provided section aliases: + +| Section Aliases | +|-------------------------| +| Umb.Section.Content | +| Umb.Section.Media | +| Umb.Section.Settings | +| Umb.Section.Packages | +| Umb.Section.Users | +| Umb.Section.Members | +| Umb.Section.Translation | + +Section View extensions can also appear in Sidebar extensions of Umbraco-provided sections, alongside custom sidebars created by authors. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section.md b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section.md new file mode 100644 index 00000000000..08860432d11 --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/sections/section.md @@ -0,0 +1,88 @@ +--- +description: Introducing Section extensions, a home for custom content and functionality. +--- + +# Section + +Umbraco extension authors can place their extension in the top-level navigation of the backoffice using Sections. The +extension will be placed among the default options such as Content, Media, Settings, etc. + +Within the section, authors can add menus, section views, workspace views, or any other content or interface they +desire. + +

Section

+ +## **Creating a section** + +### **Manifests** + +Sections can be created by adding a definition in the extension's manifest file. + +{% code title="umbraco-package.json" %} +```json +{ + "type": "section", + "alias": "My.Section", + "name": "My Section", + "meta": { + "label": "My.Section", + "pathname": "my-section" + } +} +``` +{% endcode %} + +### **Group permissions** + +To enable custom sections for backoffice users, site administrators must first assign permissions to those users. This +involves configuring the permission for a user group and assigning users to that group. + +To grant access to the custom section, open the Umbraco backoffice, navigate to the **Users** section, and select the +**User groups** menu item. Site administrators can create a new user group or modify an existing one. + +Once the user group is open, click the **Choose** button under the Sections section. Select the custom section from the +slide-out modal to enable access. + +

Enabling new Sections

+ +After assigning permission, users may need to reload the backoffice for the changes to take effect. + +

Section

+ +### **Entry points** + +When creating a new section, create an [Entry Point](../backoffice-entry-point.md) extension in the +[Umbraco Package Manifest](../../../umbraco-package.md) to complement it. Entry Point extensions add initialization and +teardown lifecycle events that may be helpful in coordinating behavior inside the section. + +## **Extend with Sidebar, Dashboards, and more** + +Sections serve as blank canvases within the Umbraco backoffice. Extension authors can integrate other Umbraco extensions +into sections, including [custom dashboards](../../../../tutorials/creating-a-custom-dashboard/), +[sidebars](section-sidebar.md), and [section views](section-view.md). + +Section authors can also skip Umbraco backoffice components and build a fully custom view by creating an empty element. + +### **Manifest with empty element** + +{% hint style="warning" %} +This approach is not recommended because it restricts content to a single element. Instead, use a Dashboard or Section View. +{% endhint %} + +{% code title="manifests.ts" %} +```typescript +const section : UmbExtensionManifest = { + type: "section", + alias: "Empty.Section", + name : 'Empty Section', + element : () => import('./empty-section.element.js'), + meta : { + label : 'Empty Section', + pathname : 'empty-section' + } +} +``` +{% endcode %} + +The element file must contain an `element`, a `default` export, or specify the element name in the +`elementName` field. diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/README.md new file mode 100644 index 00000000000..a87681d96ef --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/README.md @@ -0,0 +1,6 @@ +--- +description: >- + An overview of the available extension types related to stores and repositories. +--- + +# Extension Types: Stores and repositories diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/item-store.md b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/item-store.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/repository.md b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/repository.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/store.md b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/store.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/tree-store.md b/17/umbraco-cms/customizing/extending-overview/extension-types/stores-and-repositories/tree-store.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/theme.md b/17/umbraco-cms/customizing/extending-overview/extension-types/theme.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/tree-item.md b/17/umbraco-cms/customizing/extending-overview/extension-types/tree-item.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/tree.md b/17/umbraco-cms/customizing/extending-overview/extension-types/tree.md new file mode 100644 index 00000000000..a7da343a01c --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/tree.md @@ -0,0 +1,200 @@ +--- +description: A guide to creating a custom tree in Umbraco +--- + +# Trees + +The tree is a hierarchical structure of nodes and is registered in the Backoffice extension registry. A tree can be rendered anywhere in the Backoffice with the help of the `` element. + +{% hint style="info" %} +To see how to register a tree as a menu in a section, please refer to the [Section Sidebar](./sections/section-sidebar.md) article. +{% endhint %} + +## Creating trees + +To create a Tree in the Backoffice, you need to take multiple steps: + +### Registering a tree + +To register a tree, you need to create a manifest: + +```json +{ + "type": "tree", + "alias": "My.Tree.Alias", + "name": "My Tree", + "meta": { + "repositoryAlias": "My.Repository.Alias" + } +} +``` + +### Rendering a tree + +To render a tree in the Backoffice, you can use the `` element. You need to provide the alias of the tree you want to render. The alias is the same as the one you registered in the manifest. + +```typescript + +``` + +### Render a Custom Tree Item + +The `` element will render the tree items based on the registered tree item alias. The tree will be rendered using the [](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_tree.UmbDefaultTreeItemElement.html) element by default. If you want to render a custom tree item, you need to register a tree item manifest. This manifest can then show a custom element for the tree item. + +#### **The Tree Item Manifest** + +```json +{ + "type": "treeItem", + "alias": "Umb.TreeItem.Alias", + "name": "My Tree Item", + "element": "./my-tree-item.element.js", + "conditions": { + "entityType": "my-entity-type", + }, +}; +``` + +#### The Tree Item Element + +To create a custom tree item, you need to create a custom element. This element can optionally extend the [UmbTreeItemElementBase](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_tree.UmbTreeItemElementBase.html) class. However, it can also be used as a standalone element if you prefer to implement the tree item logic yourself. + +This example creates a custom tree item that extends the base class. The base class provides the necessary context and functionality for the tree item. + +```typescript +import type { MyTreeItemDataModel } from './my-tree-item.model.js'; +import { UmbTreeItemElementBase } from '@umbraco-cms/backoffice/tree'; +import { html, nothing, customElement } from '@umbraco-cms/backoffice/external/lit'; + +@customElement('my-tree-item') +export class MyTreeItemElement extends UmbTreeItemElementBase { + override render() { + if (!this.item) return nothing; + return html` +
+ + ${this.item.name} +
+ `; + } +} + +export default MyTreeItemElement; +``` + +#### The Tree Item Model + +To define the data model for your tree item, you can create a model that extends the [UmbTreeItemModel](https://apidocs.umbraco.com/v16/ui-api/interfaces/packages_core_tree.UmbTreeItemModel.html). This model will be used to provide the data for your custom tree item. + +{% code title="my-tree-item.model.ts" %} +```typescript +import type { UmbTreeItemModel } from '@umbraco-cms/backoffice/tree'; + +export interface MyTreeItemDataModel extends UmbTreeItemModel { + // Add any additional properties you need for your tree item +} +``` +{% endcode %} + + +### Adding data to the tree + +To add data to the tree, you need to create a repository that will provide the data for the tree. The repository is defined in the manifest of the tree and linked through its `repositoryAlias`. + +```json +{ + "type": "repository", + "alias": "My.Repository.Alias", + "name": "My Repository", + "api": "./my-repository.js" +} +``` + +#### Implementing the repository + +The repository needs to be able to fetch data for the tree. You can implement the repository as a class that extends the [UmbTreeRepositoryBase](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_tree.UmbTreeRepositoryBase.html) class. This class provides the necessary methods to fetch data for the tree. + +{% code title="my-repository.ts" %} +```typescript +import { MyTreeDataSource } from './my-tree-data-source.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbTreeRepositoryBase } from '@umbraco-cms/backoffice/tree'; + +export class MyRepository extends UmbTreeRepositoryBase { + constructor(host: UmbControllerHost) { + super(host, MyTreeDataSource); + } +} +``` +{% endcode %} + +#### Implementing the data source + +The data source is responsible for fetching the data for the tree. You can implement the data source as a class that implements the [UmbTreeDataSource](https://apidocs.umbraco.com/v16/ui-api/interfaces/packages_core_tree.UmbTreeDataSource.html) interface. + +{% code title="my-tree-data-source.ts" %} +```typescript +import type { MyTreeItemModel } from './my-tree-item.model.js'; +import type { + UmbTreeAncestorsOfRequestArgs, + UmbTreeChildrenOfRequestArgs, + UmbTreeDataSource, + UmbTreeRootItemsRequestArgs, +} from '@umbraco-cms/backoffice/tree'; + +export class MyTreeDataSource implements UmbTreeDataSource { + async getRootItems(args: UmbTreeRootItemsRequestArgs) { + // Fetch the root items for the tree + return [ + { + id: 'root1', + name: 'Root Item 1', + icon: 'icon-folder', + }, + { + id: 'root2', + name: 'Root Item 2', + icon: 'icon-folder', + }, + ]; + } + + async getChildrenOf(args: UmbTreeChildrenOfRequestArgs) { + // Fetch the children of the specified item + if (args.id === 'root1') { + return [ + { + id: 'child1', + name: 'Child Item 1', + icon: 'icon-document', + }, + { + id: 'child2', + name: 'Child Item 2', + icon: 'icon-document', + }, + ]; + } + return []; + } + + async getAncestorsOf(args: UmbTreeAncestorsOfRequestArgs) { + // Fetch the ancestors of the specified item + if (args.id === 'child1') { + return [ + { + id: 'root1', + name: 'Root Item 1', + icon: 'icon-folder', + }, + ]; + } + return []; + } +} +``` +{% endcode %} + +## Further reading + +For more information on trees, you can refer to the examples folder in the GitHub repository: [Umbraco UI Examples - Trees](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Web.UI.Client/examples/tree) diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/ufm-component.md b/17/umbraco-cms/customizing/extending-overview/extension-types/ufm-component.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/user-profile-app.md b/17/umbraco-cms/customizing/extending-overview/extension-types/user-profile-app.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/README.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/README.md new file mode 100644 index 00000000000..5581b2339ac --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/README.md @@ -0,0 +1,6 @@ +--- +description: >- + An overview of the available extension types related to workspaces. +--- + +# Extension Types: Workspaces diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-action-menu-item.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-action-menu-item.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context.md new file mode 100644 index 00000000000..2000323ca5c --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context.md @@ -0,0 +1,135 @@ +--- +description: Establish an extension to communicate across the application. +--- + +# Workspace Context + +The general Workspace Context is a container for the data of a workspace. It is a wrapper around the data of the entity that the workspace is working on. It is responsible for loading and saving the data to the server. Workspace Contexts are used to bring additional context alongside the default context of a workspace. + +* A workspace context knows about its entity type (for example content, media, member, etc.) and holds its unique string (for example: key). +* Most workspace contexts hold a draft state of its entity data. It is a copy of the entity data that can be modified at runtime and sent to the server to be saved. + +You can add additional Workspace Contexts using the `workspaceContext` Extension Type, which allows you to inject custom logic into your own Workspace or another one. + +## Example of Workspace Context + +The API will be initiated with the same host as the default Workspace Context. + +```typescript +{ + type: 'workspaceContext', + alias: 'My.WorkspaceContext.Counter', + name: 'My Counter Context', + api: 'my-workspace-counter.context.js', + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: 'Umb.Workspace.Document', + } + ] +} +``` + +The code for such an API file might look like this: + +```typescript +import { + UmbController, + UmbControllerHost, +} from "@umbraco-cms/backoffice/controller-api"; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; +import { UmbContextToken } from "@umbraco-cms/backoffice/context-api"; +import { UmbNumberState } from "@umbraco-cms/backoffice/observable-api"; + +export class MyContextApi extends UmbContextBase { + #counter = new UmbNumberState(0); + readonly counter = this.#counter.asObservable(); + + constructor(host: UmbControllerHost) { + super(host, My_COUNTER_CONTEXT); + } + + increment() { + this.#counter.next(this.#counter.value + 1); + } +} + +// Important to export as api for the Extension Registry to pick up the class: +export const api = MyContextCounterApi; +``` + +A Context Token for a Workspace Context Extension should look like this: + +```typescript +export const My_COUNTER_CONTEXT = new UmbContextToken( + "UmbWorkspaceContext", + "My.WorkspaceContext.Counter" +); +``` + +It is recommended to use `UmbWorkspaceContext` as the Context Alias for your Context Token. This will ensure that the requester only retrieves this Context if it's present at their nearest Workspace Context. Use the Extension Manifest Alias as the API Alias for your Context Token to ensure its unique. For more information, see the [Context API](../../../foundation/context-api/) article. + +## Use the Workspace Context + +The following example declares an element that will be present in the same workspace for which the workspace context is provided. In this particular example, it is a workspace view that will be registered to the `Umb.Workspace.Document` workspace. + +```typescript +import { My_COUNTER_CONTEXT } from './example-workspace-context.js'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { css, html, customElement, state, LitElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; + +@customElement('example-counter-workspace-view') +export class ExampleCounterWorkspaceView extends UmbElementMixin(LitElement) { + + #counterContext?: typeof My_COUNTER_CONTEXT.TYPE; + + @state() + private count = 0; + + constructor() { + super(); + this.consumeContext(My_COUNTER_CONTEXT, (context) => { + this.#counterContext = context; + this.observe(this.#counterContext.counter, (count) => { + this.count = count; + }); + } + + #onClick() { + this.#counterContext?.increment(); + } + + override render() { + return html` + Current count value: ${this.count} + + `; + } +} + +// Important to export as 'element' otherwise the Extension Registry cannot pick up the class. +export const element = ExampleCounterWorkspaceView +``` + +Manifest to register this: + +
{
+    type: 'workspaceView',
+    name: 'Example Counter Workspace View',
+    alias: 'example.workspaceView.counter',
+    element: () => import('./example-workspace-view.js'),
+    weight: 900,
+    meta: {
+        label: 'Counter',
+        pathname: 'counter',
+        icon: 'icon-lab',
+    },
+    conditions: [
+        {
+	    alias: UMB_WORKSPACE_CONDITION_ALIAS,
+            match: 'Umb.Workspace.Document',
+        },
+    ],
+}
+
diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-editor-actions.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-editor-actions.md new file mode 100644 index 00000000000..2eb896ea50a --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-editor-actions.md @@ -0,0 +1,55 @@ +# Workspace Actions + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Workspace actions are a set of functionalities or operations that can be performed within a workspace. These actions involve creating documents within the workspace, organizing and categorizing documents, publishing content and so on. + +Workspace action relates to a workspace alias (Umb.Workspace.Document) and has Access to the workspace context. + +

Workspace Actions

+ +**JavaScript Manifest example** + +
import { extensionRegistry } from '@umbraco-cms/extension-registry';
+import { MyWorkspaceAction } from './my-workspace-action';
+
+const manifest = {
+ type: 'workspaceAction',
+ alias: 'My.WorkspaceAction',
+ name: 'My Workspace Action',
+ api: MyWorkspaceAction,
+ meta: {
+  label: 'My Action',
+ },
+ conditions: [
+  {
+   alias: 'Umb.Condition.WorkspaceAlias',
+   match: 'My.Workspace',
+  },
+ ],
+};
+
+extensionRegistry.register(manifest);
+
+ +## The Workspace Action Class + +As part of the Extension Manifest you can attach a class that will be instantiated as part of the action. It will have access to the host element and the Workspace Context. When the action is clicked the `execute` method on the API class will be run. When the action is completed, an event on the host element will be dispatched to notify any surrounding elements. + +```ts +import { UmbWorkspaceActionBase } from '@umbraco-cms/backoffice/workspace'; + +export class MyWorkspaceAction extends UmbWorkspaceActionBase { + execute() { + this.workspaceContext.myAction(this.selection); + } +} +``` + +**Default Element** + +```typescript +interface UmbWorkspaceActionElement {} +``` diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-footer-app.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-footer-app.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views.md new file mode 100644 index 00000000000..9c21aacd57c --- /dev/null +++ b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views.md @@ -0,0 +1,100 @@ +--- +description: Append a view to any Workspace +--- + +# Workspace Views + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +{% hint style="info" %} +Workspace Views was previously called Content Apps. +{% endhint %} + +Workspace Views are customizable companion **tabs** with the ability to take place in any workspace. + +

Workspace Views

+ +**In Content Section** + +With Workspace Views, editors can switch from editing 'Content' to accessing contextual information related to the item they are editing. + +The default workspace view is **'Info'** - displaying Links, History and Status of the current content item. + +## Example of a Workspace View + +1. Follow the [Vite Package Setup](../../../development-flow/vite-package-setup.md) by creating a new project folder called "`workspaceview`" in `App_Plugins`. +2. Create a manifest file named `umbraco-package.json` at the root of the `workspaceview` folder. Here we define and configure our workspace view. +3. Add the following code to `umbraco-package.json`: + +{% code title="umbraco-package.json" lineNumbers="true" %} +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My workspace", + "version": "0.1.0", + "extensions": [ + { + "type": "workspaceView", + "alias": "My.WorkspaceView", + "name": "My Workspace View", + "element": "/App_Plugins/workspaceview/dist/workspaceview.js", + "meta": { + "label": "My Workspace View", + "pathname": "/my-workspace-view", + "icon": "icon-add" + }, + "conditions": [ + { + "alias": "Umb.Condition.WorkspaceAlias", + "match": "Umb.Workspace.Document" + } + ] + } + ] +} +``` +{% endcode %} + +4. Add the following code to the existing `my-element.ts` from the `src`folder: + +{% code title="my-element.ts" lineNumbers="true" %} +```typescript +import { LitElement, html, customElement, css } from "@umbraco-cms/backoffice/external/lit"; +import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; + +@customElement('my-workspaceview') +export default class MyWorkspaceViewElement extends UmbElementMixin(LitElement) { + + render() { + return html` + + Welcome to my newly created workspace view. + + ` + } + + static styles = css` + uui-box { + margin: 20px; + } + ` +} + +declare global { + interface HTMLElementTagNameMap { + 'my-workspaceview': MyWorkspaceViewElement + } +} + +``` +{% endcode %} + +In the `workspaceview` folder run `npm run build` and then run the project. Then in the content section of the Backoffice you will see our new Workspace View: + +

Workspace View Example

+ +{% hint style="info" %} +To see the Workspace View that we have created in the content section, first you will need to have some content created. +{% endhint %} diff --git a/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace.md b/17/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/17/umbraco-cms/customizing/foundation/README.md b/17/umbraco-cms/customizing/foundation/README.md new file mode 100644 index 00000000000..338eeda0f22 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/README.md @@ -0,0 +1,39 @@ +--- +description: >- + In this section, you will learn about the general framework of Backoffice. How + to integrate and communicate and make your own reactive UI. +--- + +# Foundation + +## [Terminology](terminology.md) + +Get an overview of the general terms in the Umbraco Backoffice and what they represent. + +## [Umbraco Element](umbraco-element/) + +The Umbraco element brings what you need to integrate your UI. + +## [Lit Element](lit-element.md) + +Learn about Lit Element, the Web Component Framework that most examples and most of the Backoffice are based upon. + +## [Context API](context-api/) + +Learn how to communicate with the rest of the application, whether you want to retrieve data or manipulate it. + +## [States — Make reactive UI](states.md) + +Bring life into your UI by ensuring it's up to date with the current data. + +## [Sorting](sorting.md) + +Create a UI that the user can sort via Drag and Drop. + +## [Routes](routes.md) + +Implements routes into your UI, enabling Users to deep link into your UI. + +## [Community Resources](https://github.com/umbraco/Umbraco.Packages/tree/main/bellissima) + +An overview of community articles related to the New backoffice "Bellissima". diff --git a/17/umbraco-cms/customizing/foundation/context-api/README.md b/17/umbraco-cms/customizing/foundation/context-api/README.md new file mode 100644 index 00000000000..8376f56399e --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/context-api/README.md @@ -0,0 +1,9 @@ +--- +description: The Context API is your tool to integrate with the application +--- + +# Context API + +The Context API enables receiving APIs. Depending on where your code is executed from, it affects which and what instances of APIs can be received. The DOM structure defines the scope of who can gain access to what APIs. This is because the APIs are provided via an element and can then only be consumed by code running on itself or descendant elements. + +## diff --git a/17/umbraco-cms/customizing/foundation/context-api/consume-a-context.md b/17/umbraco-cms/customizing/foundation/context-api/consume-a-context.md new file mode 100644 index 00000000000..aa981dfacc2 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/context-api/consume-a-context.md @@ -0,0 +1,199 @@ +--- +description: >- + Consuming a Context via the Context API is the way to start the communication + with the rest of the application +--- + +# Consume a Context + +## Start consuming + +There are different ways to consume a Context API. The most straightforward implementation is done on an [Umbraco Element](../umbraco-element/) with a Context Token. + +All Umbraco Context APIs have a Context Token which can be imported and used for consumption, for example: + +```typescript +import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; + +... + +this.consumeContext(UMB_NOTIFICATION_CONTEXT, (context) => { + // Notice this is a subscription, meaning the context can change and even disappear again. + if (context) { + console.log("I've got the Notification Context: ", context); + } else { + console.log("The Notification Context is gone, I will make sure my code disassembles properly.") + } +}); +``` + +The above example takes place in an Umbraco Element or Umbraco Controller. + +### Alternative solutions + +The above examples utilize an Umbraco Controller to hook into an element's life cycle. This Controller is named `UmbContextConsumerController`. + +If you need to consume a Context API from a non-controller host, then look at the `UmbContextConsumer`. + +## Get a context once + +You can retrieve a Context without getting updated if the Context disconnects or another better Context matches your request. + +This is useful if your code is a one-time execution, for example, when the user triggers an action that needs to communicate with a context: + +
async execute() {
+    const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT);
+    if (!notificationContext) {
+	throw new Error('Notification context not found');
+    }
+    const notification = { data: { message: `High five, you executed this method!` } };
+    notificationContext.peek('positive', notification);
+}
+
+ +## **Write your own Context Token** + +A Context Token is a context identifier and is generally a string matched with a type. In this way, users of the token can be sure to get the right type of context. + +```typescript +import { UmbContextToken } from "@umbraco-cms/backoffice/context-api"; + +type MyContext = { + foo: string; + bar: number; +}; + +const MY_CONTEXT = new UmbContextToken ("My.Context.Token"); +``` + +### **Context Token with an API Alias** + +For additions to already existing Contexts, the API Aliases should be used to identify the additional API. Using the same Context Alias for additional APIs will ensure that such API must be present with the first encounter of that Context Alias. Otherwise, a request will be rejected. In other words, if the addition is not part of the nearest matching Context, the request will be rejected. + +For a concrete example of this in practice, read the [Extension Type Workspace Context](../../extending-overview/extension-types/workspaces/workspace-context.md) article. + +{% hint style="info" %} +Using API Alias is highlight recommended when implementing Additional Contexts to Existing Contexts. Most Context extensions should do this. +{% endhint %} + +```typescript +import { UmbContextToken } from "@umbraco-cms/backoffice/context-api"; + +type MyAdditionalContext = { + additional: string; +}; + +const MY_ADDITIONAL_API_TOKEN = new UmbContextToken( + "My.ContextFrame.Alias", + "My.API.Alias" +); +``` + +The Token declared above can be used to provide an additional Context API at the same Element as another Context API is provided at. Below is an example of how the two APIs are made available. + +```typescript +const contextElement = new UmbLitElement(); +contextElement.provideContext( + MY_API_TOKEN, + new MyAPiFromSomewhereNotPartOfThisExample() +); +contextElement.provideContext( + MY_ADDITIONAL_API_TOKEN, + new MyAdditionalAPiFromSomewhereNotPartOfThisExample() +); + +const consumerElement = new UmbLitElement(); +contextElement.appendChild(consumerElement); +consumerElement.consumeContext(MY_API_TOKEN, (context) => { + console.log("I've got the default api", context); +}); +consumerElement.consumeContext(MY_ADDITIONAL_API_TOKEN, (context) => { + console.log("I've got the additional api", context); +}); +``` + +This is no different than using two different Context Aliases. But it has an important effect on what happens if one of them is not provided. This is demonstrated in the example below: + +```typescript +const upperContextElement = new UmbLitElement(); + +const contextElement = new UmbLitElement(); +upperContextElement.appendChild(contextElement); +contextElement.provideContext( + MY_API_TOKEN, + new MyAPiFromSomewhereNotPartOfThisExample() +); + +const consumerElement = new UmbLitElement(); +contextElement.appendChild(consumerElement); +consumerElement.consumeContext(MY_API_TOKEN, (context) => { + console.log("I've got the default api", context); +}); +consumerElement.consumeContext(MY_ADDITIONAL_API_TOKEN, (context) => { + // This will never happen + console.log("I will just get undefined: ", context); +}); +``` + +The consumption of the Additional API will never happen as the token uses the same Context Alias as `MY_API_TOKEN`. This means that any request containing this Context Alias will be stopped at the first API it encounters. To ensure addition to a specific context, do it locally at the nearest API that uses the same Context Alias. + +### **Context Token with a Type Discriminator** + +{% hint style="info" %} +This is only relevant if you are going to make multiple context API for the same context. Discriminator only gives value for consumption of Context APIs that have a varying interface. The backoffice uses this for the different types of Workspace Contexts. +{% endhint %} + +In some cases, it is needed to have different APIs for the same context. For example, the [Workspace Contexts](../../extending-overview/extension-types/workspaces/workspace-context.md). + +If someone wants the workspace name, they might not care about the specific API of the Workspace Context. These implementations can use a standard Context Token with a type of generic Workspace Context. + +The features related to Publishing in the **Document Workspace Context** do not require a new Context. However, we should not accidentally retrieve the workspace context of a parent workspace when in a Workspace. Therefore, we need to provide a workspace context in each workspace, and the one we retrieve is the one we will be using. Since Publishing is not part of the generic Workspace Context, check if the context is a Document Workspace Context and recast it accordingly. + +To avoid each implementation taking care of this, Context Tokens can be extended with a **Type Discriminator**. This will discard the given API if it does not meet the necessary requirements. When it is the desired type, the API will be converted to the appropriate type. + +This example shows how to create a discriminator Context Token that will discard the API if it is not a Publishable Context: + +**Context Token Example:** + +```typescript +import { UmbContextToken } from "@umbraco-cms/backoffice/context-api"; + +interface MyBaseContext { + foo: string; + bar: number; +} + +interface MyPublishableContext extends MyBaseContext { + publish(); +} + +const MY_PUBLISHABLE_CONTEXT = new UmbContextToken< + + MyContext, + MyPublishableContext +>("My.Context.Token", undefined, (context): context is MyPublishableContext => { + return "publish" in context; +}); +``` + +**Implementation of Context Token Example:** + +```typescript +const contextElement = new UmbLitElement(); +contextElement.provideContext( + MY_PUBLISHABLE_CONTEXT, + new MyPublishableContext() +); + +const consumerElement = new UmbLitElement(); +contextElement.appendChild(contextElement); +consumerElement.consumeContext(MY_PUBLISHABLE_CONTEXT, (context) => { + + // context is of type 'MyPublishableContext' + console.log("I've got the context of the right type", context); +}); +``` + +This allows implementers to request a publishable context without needing to know the Type or how to identify the context. + +In detail, the Context API will search for the first API that matches the alias `My.Context.Token`, and not look further. If the API meets the type discriminator, it will be returned, otherwise the consumer will never reply. diff --git a/17/umbraco-cms/customizing/foundation/context-api/provide-a-context.md b/17/umbraco-cms/customizing/foundation/context-api/provide-a-context.md new file mode 100644 index 00000000000..af871da36c4 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/context-api/provide-a-context.md @@ -0,0 +1,39 @@ +--- +description: >- + Providing a Context enables distant code to communicate with it, ideal way to + incorporate central logic. +--- + +# Provide a Context + +## Provide a Context API + +The recommended approach is to base your Context API on the `UmbContextBase` class, which provides automatic context registration. The following example shows how it's used: + +```typescript +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; + +export class MyCustomContext extends UmbContextBase { + constructor(host: UmbControllerHost) { + super(host, MY_CUSTOM_CONTEXT); + } +} + +export const MY_CUSTOM_CONTEXT = new UmbContextToken( + 'MyCustomContextUniqueAlias', +); +``` + +For a practical implementation example, see the [Extension Type Workspace Context](../../extending-overview/extension-types/workspaces/workspace-context.md) article. + +You can provide a Context API from any Umbraco Element or Umbraco Controller: + +```typescript +this.provideContext('myContextAlias', new MyContextApi()); +``` + +Or provide it from a Controller using a `host` reference to the Controller Host (Umbraco Element/Controller): + +```typescript +new UmbContextProviderController(host, 'myContextAlias', new MyContextApi()); +``` diff --git a/17/umbraco-cms/customizing/foundation/contexts/README.md b/17/umbraco-cms/customizing/foundation/contexts/README.md new file mode 100644 index 00000000000..4e011c85ef9 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/contexts/README.md @@ -0,0 +1,15 @@ +--- +description: Contexts +--- + +# Contexts + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Below you can find some articles on how you can work with different contexts: + +## [Property Dataset Context](property-dataset-context.md) + +A Dataset Context is the connection point between a Property Editor and a Workspace and covers a set of properties. diff --git a/17/umbraco-cms/customizing/foundation/contexts/property-dataset-context.md b/17/umbraco-cms/customizing/foundation/contexts/property-dataset-context.md new file mode 100644 index 00000000000..d159abe7d0a --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/contexts/property-dataset-context.md @@ -0,0 +1,64 @@ +--- +description: >- + The owner of the values for properties, enabling you to communicate with other + properties. +--- + +# Property Dataset Context + +Property Editors UIs require a Dataset Context to be present for them to work. This enables Property Editor UIs to have a generic relationship with their ownership and work in various cases. + +The Dataset Context holds a name for the entity and a set of property values. + +Retrieve a reference to the Property Dataset Context to start communicating: + +```typescript +this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (context) => { + ... +}); +``` + +### Observe the value of another Property + +Observe a value if you are using it in your UI. In the following example, the \`alias\` is used to retrieve the value of another property: + +```typescript +this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (context) => { + this.observe( + await context?.propertyValueByAlias("alias-of-other-property"), + (value) => { + console.log("the value of the other property", value) + } + ); +}); +``` + +### Set the value of another Property + +You can alter the value of another property in this way: + +```typescript +this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (context) => { + this.datasetContext = context; +}); + +... + +updateValue() { + this.datasetContext?.setPropertyValue("alias-of-other-property", "The updated value"); +} +``` + +### Dataset Context in relation to Property Editors and Workspaces + +A Dataset Context is the connection point between a Property Editor and a Workspace. + +The Workspace has the root ownership, where the Dataset represents a specific Variant. + +The hierarchy is as follows: + +* Workspace Context + * Property Dataset Context + * Property Editor UIs + +If you want to set or read values from properties of the same variant, use the Property Dataset Context. If you need values from another variant, use the Workspace Context instead. diff --git a/17/umbraco-cms/customizing/foundation/fetching-data/README.md b/17/umbraco-cms/customizing/foundation/fetching-data/README.md new file mode 100644 index 00000000000..4cc63c1062d --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/fetching-data/README.md @@ -0,0 +1,57 @@ +--- +description: Learn how to request data when extending the Backoffice. +--- + +# Fetching Data + +## Fetch Data Through HTTP + +There are two main ways to fetch data through HTTP in the Umbraco Backoffice: + +* [Fetch API](./#fetch-api) +* [Umbraco HTTP Client](./#umbraco-http-client). + +The Fetch API is a modern way to make network requests in JavaScript, while the Umbraco HTTP client is a wrapper around it, providing a more convenient interface. + +For most scenarios, the Umbraco HTTP Client is recommended because it: + +* Automatically handles authentication and error handling. +* Provides type safety for requests and responses. +* Simplifies request and response parsing. +* Integrates seamlessly with the Backoffice. + +The Fetch API is an alternative for simpler use cases. + +The following table provides a comparison of the two options: + +| Feature | [Fetch API](fetch-api.md) | [Umbraco HTTP Client](http-client.md) | +| -------------------- | ------------------------- | ------------------------------------- | +| Authentication | Manual | Automatic | +| Error Handling | Manual | Built-in | +| Type Safety | No | Yes | +| Request Cancellation | Yes (via AbortController) | Yes (via AbortController) | +| Recommended Use Case | Common requests | Complex or frequent requests | + +After selecting a method, refer to the sections below for implementation details and guidance on handling the received data. + +### [Fetch API](fetch-api.md) + +The Fetch API is a modern way to make network requests in JavaScript. It provides a more powerful and flexible feature set than the older XMLHttpRequest. + +### [Umbraco HTTP Client](http-client.md) + +The Umbraco HTTP Client is a wrapper around the Fetch API that provides a more convenient way to make network requests. It handles request and response parsing, error handling, and retries. + +## Handle Requests + +Once you have chosen a method to fetch data, the next step is to handle the execution of requests. This includes managing errors, refreshing tokens, and ensuring proper authentication. + +## [Executing Requests](try-execute.md) + +After fetching data, the next step is to execute the request. You can use the `tryExecute` function to handle errors and refresh the token if it is expired. + +## Advanced Topics + +### [Custom Generated Client](custom-generated-client.md) + +For advanced scenarios, you can generate a custom client for your API using tools like [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts). This approach is ideal when working with custom API controllers or when you need type-safe, reusable client code. diff --git a/17/umbraco-cms/customizing/foundation/fetching-data/custom-generated-client.md b/17/umbraco-cms/customizing/foundation/fetching-data/custom-generated-client.md new file mode 100644 index 00000000000..3b86ed603aa --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/fetching-data/custom-generated-client.md @@ -0,0 +1,99 @@ +--- +description: Learn how to create a custom generated client with TypeScript types for your OpenAPI specification. +--- + +# Custom Generated Client + +Umbraco uses [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/get-started) to generate its HTTP client for the OpenAPI specification of the Management API. It is available through the `@umbraco-cms/backoffice/http-client` package. + +{% content-ref url="http-client.md" %} +[http-client.md](http-client.md) +{% endcontent-ref %} + +The following examples show how to generate a client from an OpenAPI specification and how to use it in the project. Below, the `@hey-api/openapi-ts` library is used, but the same principles apply to any other library that generates a TypeScript client. + +## Generate your own client + +The generated client provides a convenient way to make requests to the specified API with type-safety without having to manually write the requests yourself. Consider generating a client to save time and reduce effort when working with custom API controllers. + +To get started, install the generator using the following command: + +```bash +npm install @hey-api/openapi-ts +``` + +Then, use the `openapi-ts` command to generate a client from your OpenAPI specification: + +```bash +npx openapi-ts --input https://example.com/openapi.json --output ./my-client +``` + +This will generate a TypeScript client in the `./my-client` folder. Import the generated client into your project to make requests to the Management API. + +To learn more about OpenAPI and how to define your API specification, visit the [OpenAPI Documentation](https://swagger.io/specification/). + +## Connecting to the Management API + +You will need to set up a few configuration options in order to connect to the Management API. The following options are required: + +- `auth`: The authentication method to use. This is typically `Bearer` for the Management API. +- `baseUrl`: The base URL of the Management API. This is typically `https://example.com/umbraco/api/management/v1`. +- `credentials`: The credentials to use for the request. This is typically `same-origin` for the Management API. + +You can set these options either directly with the `openapi-ts` command or in a central place in your code. For example, you can create a [BackofficeEntryPoint](../../extending-overview/extension-types/backoffice-entry-point.md) that sets up the configuration options for the HTTP client: + +```javascript +import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth'; +import { client } from './my-client/client.gen'; + +export const onInit = (host) => { + host.consumeContext(UMB_AUTH_CONTEXT, (authContext) => { + // Get the token info from Umbraco + const config = authContext?.getOpenApiConfiguration(); + + client.setConfig({ + auth: config?.token ?? undefined, + baseUrl: config?.base ?? "", + credentials: config?.credentials ?? "same-origin", + }); + }); +}; +``` + +This sets up the HTTP client with the Management API’s base URL and authentication method.. You can then use the client to make requests to the Management API. + +{% hint style="info" %} +See the example in action in the [Umbraco Extension Template](../../development-flow/umbraco-extension-template.md). +{% endhint %} + +### Fetch API + +A Backoffice Entry Point is recommended when working with multiple requests. However, if you only have a few requests to make, you can use the `fetch` function directly. Read more about that here: + +{% content-ref url="fetch-api.md" %} +[fetch-api.md](fetch-api.md) +{% endcontent-ref %} + +**Setting the client directly** +You can also set the client directly in your code. This is useful if you only have a few requests to make and don't want to set up a Backoffice Entry Point. + +```javascript +import { getMyControllerAction } from './my-client'; +import { tryExecute } from '@umbraco-cms/backoffice/resources'; +import { umbHttpClient } from '@umbraco-cms/backoffice/http-client'; + +const { data } = await tryExecute(this, getMyControllerAction({ + client: umbHttpClient, // Use Umbraco's HTTP client +})); + +if (data) { + console.log('Server status:', data); +} +``` + +The above example shows how to use the `getMyControllerAction` function, which is generated through `openapi-ts`. The `client` parameter is the HTTP client that you want to use. You can use any HTTP client that implements the underlying interface from `@hey-api/openapi-ts`, which the Umbraco HTTP Client does. The `getMyControllerAction` function will then use the Umbraco HTTP client over its own to make the request to the Management API. + +## Further reading + +- [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/get-started) +- [Creating a Backoffice API](../../../tutorials/creating-a-backoffice-api/README.md) diff --git a/17/umbraco-cms/customizing/foundation/fetching-data/fetch-api.md b/17/umbraco-cms/customizing/foundation/fetching-data/fetch-api.md new file mode 100644 index 00000000000..211c5fab17d --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/fetching-data/fetch-api.md @@ -0,0 +1,184 @@ +--- +description: >- + The Fetch API is a modern way to make network requests in JavaScript. It + provides a more powerful and flexible feature set than the older + XMLHttpRequest. +--- + +# Fetch API + +The [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a Promise-based API that allows you to make network requests similar to XMLHttpRequest. It is a modern way to make network requests in JavaScript and provides a more powerful and flexible feature set than the older XMLHttpRequest. It is available in all modern browsers and is the recommended way to make network requests in JavaScript. + +## Fetch API in Umbraco + +The Fetch API can also be used in Umbraco to make network requests to the server. Since it is built into the browser, you do not need to install any additional libraries or packages to use it. The Fetch API is available in the global scope and can be used directly in your JavaScript code.\ +The Fetch API is a great way to make network requests in Umbraco because it provides a lot of flexibility. You can use it to make GET, POST, PUT, DELETE, and other types of requests to the server. You can also use it to handle responses in a variety of formats, including JSON, text, and binary data. + +### Example + +For this example, we are using the Fetch API to make a GET request to the `/umbraco/MyApiController/GetData` endpoint. The response is then parsed as JSON and logged to the console. + +{% hint style="info" %} +The example assumes that you have a controller set up at the `/umbraco/MyApiController/GetData` endpoint that returns JSON data. You can replace this with your own endpoint as needed. Read more about creating a controller in the [Controllers](../../../implementation/controllers.md) article. +{% endhint %} + +If there is an error with the request, it is caught and logged to the console: + +```javascript +const data = await fetch('/umbraco/MyApiController/GetData') + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .catch(error => { + console.error('There was a problem with the fetch operation:', error); + }); + +if (data) { + console.log(data); // Do something with the data +} +``` + +{% hint style="warning" %} +When using the Fetch API, you need to manually handle errors and authentication. For most scenarios, we recommend using the Umbraco HTTP Client, which provides built-in error handling and authentication. +{% endhint %} + +## Authentication + +When making requests to the Umbraco API controllers, you may need to include an authorization token in the request headers. This is especially important when making requests to endpoints that require authentication. + +The Fetch API does not automatically include authentication tokens in requests. You need to manually add the authentication token to the request headers. While you can manage tokens manually, the recommended approach in the Backoffice is to use the **UMB\_AUTH\_CONTEXT**. This context provides tools to manage authentication tokens and ensures that your requests are properly authenticated. + +### Example: Using `UMB_AUTH_CONTEXT` for Authentication + +{% hint style="info" %} +The example assumes that you have a valid authentication token. You can replace this with your own token as needed. Read more about authentication in the [Security](../../../implementation/security.md) article. +{% endhint %} + +The following example demonstrates how to use `UMB_AUTH_CONTEXT` to retrieve the latest token and make an authenticated request: + +```javascript +import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth'; + +async function fetchData(host, endpoint) { + const authContext = await host.getContext(UMB_AUTH_CONTEXT); + const token = await authContext?.getLatestToken(); + + const response = await fetch(endpoint, { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error('Failed to fetch data'); + } + + return response.json(); +} + +// Example usage +const data = await fetchData(this, '/umbraco/management/api/v1/server/status'); +console.log(data); +``` + +{% hint style="warning" %} +When using the Fetch API with `UMB_AUTH_CONTEXT`, you need to handle token expiration errors manually. If the token is expired, the request will return a 401 error. You will need to refresh the token or prompt the user to log in again. +{% endhint %} + +Why Use **UMB\_AUTH\_CONTEXT**? + +* Simplifies Token Management: Automatically retrieves and refreshes tokens when needed. +* Aligns with Best Practices: Ensures your requests are authenticated in a way that integrates seamlessly with the Backoffice. +* Reduces Errors: Avoids common pitfalls like expired tokens or incorrect headers. + +{% hint style="info" %} +The **UMB\_AUTH\_CONTEXT** is only available in the Backoffice. For external applications, you will need to manage tokens manually or use an API user. Read more about API users in the [API Users](../../../fundamentals/data/users/api-users.md) article. +{% endhint %} + +## Management API Controllers + +The Fetch API can also be used to make requests to the Management API controllers. The Management API is a set of RESTful APIs that allow you to interact with Umbraco programmatically. You can use the Fetch API to make requests to the Management API controllers like you would with any other API. The Management API controllers are located in the `/umbraco/api/management` namespace. You can use the Fetch API to make requests to these controllers like you would with any other API. + +### API User + +You can create an API user in Umbraco to authenticate requests to the Management API. This is useful for making requests from external applications or services. You can create an API user in the Umbraco backoffice by going to the Users section and creating a new user with the "API" role. Once you have created the API user, you can make requests to the Management API using the API user's credentials. You can find these in the Umbraco backoffice. + +You can read more about this concept in the [API Users](../../../fundamentals/data/users/api-users.md) article. + +### Backoffice Token + +The Fetch API can also be used to make requests to the Management API using a Backoffice token. This is useful for making requests from custom components that are running in the Backoffice. The concept is similar to the API Users, but the Backoffice token represents the current user in the Backoffice. You will share the access policies of the current user, so you can use the token to make requests on behalf of the current user. + +To use the Backoffice access token, you will have to consume the **UMB\_AUTH\_CONTEXT** context. This context is only available in the Backoffice and includes tools to hook on to the authentication process. You can use the [getOpenApiConfiguration](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_auth.UmbAuthContext.html#getopenapiconfiguration) method to get a configuration object that includes a few useful properties: + +* `base`: The base URL of the Management API. +* `credentials`: The credentials to use for the request. +* `token()`: A function that returns the current access token. + +Read more about this in the [UmbOpenApiConfiguration](https://apidocs.umbraco.com/v16/ui-api/interfaces/packages_core_auth.UmbOpenApiConfiguration.html) interface. + +It is rather tiresome to manually add the token to each request. Therefore, you can wrap the Fetch API in a custom function that automatically adds the token to the request headers. This way, you can use the Fetch API without worrying about adding the token manually: + +```typescript +import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth'; +import type { UmbClassInterface } from '@umbraco-cms/backoffice/class-api'; + +/** + * Make an authorized request to any Backoffice API. + * @param host A reference to the host element that can request a context. + * @param url The URL to request. + * @param method The HTTP method to use. + * @param body The body to send with the request (if any). + * @returns The response from the request as JSON. + */ +async function makeRequest(host: UmbClassInterface, url: string, method = 'GET', body?: any) { + const authContext = await host.getContext(UMB_AUTH_CONTEXT); + const token = await authContext?.getLatestToken(); + const response = await fetch(url, { + method, + body: body ? JSON.stringify(body) : undefined, + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }); + return response.json(); +} +``` + +The above example illustrates the process of making a request to the Management API. You can use this function to make requests to any endpoint in the Management API. The function does not handle errors or responses, so you will need to add that logic yourself, nor does it handle the authentication process. If the token is timed out, you will get a 401 error back, if the `getLatestToken` method failed to refresh the token. + +## Executing the request + +Regardless of method, you can execute the fetch requests through Umbraco's [tryExecute](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_auth.UmbAuthContext.html#tryexecute) function. This function will handle any errors that occur during the request and will automatically refresh the token if it is expired. If the session is expired, the function will also make sure the user logs in again. + +**Example:** + +```javascript +import { tryExecute } from '@umbraco-cms/backoffice/resources'; + +const request = makeRequest(this, '/umbraco/management/api/v1/server/status'); +const response = await tryExecute(this, request); + +if (response.error) { + console.error('There was a problem with the fetch operation:', response.error); +} else { + console.log(response); // Do something with the data +} +``` + +You can read more about the `tryExecute` function in this article: + +{% content-ref url="try-execute.md" %} +[try-execute.md](try-execute.md) +{% endcontent-ref %} + +## Conclusion + +The Fetch API is a powerful and flexible way to make network requests in JavaScript. It is available in all modern browsers and is the recommended way to make network requests in JavaScript. The Fetch API can be used in Umbraco to make network requests to the server. It can also be used to make requests to the Management API controllers. You can use the Fetch API to make requests to any endpoint in the Management API. You can also use it to handle responses in a variety of formats. This is useful if you only need to make a few requests. + +However, if you have a lot of requests to make, you might want to consider an alternative approach. You could use a library like [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/get-started) to generate a TypeScript client. The library requires an OpenAPI definition and allows you to make requests to the Management API without having to manually write the requests yourself. The generated client will only need the token once. This can save you a lot of time and effort when working with the Management API. The Umbraco Backoffice itself is running with this library and even exports its internal HTTP client. You can read more about this in the [HTTP Client](http-client.md) article. diff --git a/17/umbraco-cms/customizing/foundation/fetching-data/http-client.md b/17/umbraco-cms/customizing/foundation/fetching-data/http-client.md new file mode 100644 index 00000000000..502d4adaa78 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/fetching-data/http-client.md @@ -0,0 +1,54 @@ +--- +description: Learn more about working with the Umbraco HTTP Client. +--- + +# Umbraco HTTP Client + +The Umbraco Backoffice includes a built-in HTTP client commonly referred to as the Umbraco HTTP Client for making network requests. It is generated using `@hey-api/openapi-ts` around the OpenAPI specification and is available through the `@umbraco-cms/backoffice/http-client` package. + +**Example:** + +```javascript +import { umbHttpClient } from '@umbraco-cms/backoffice/http-client'; + +const { data } = await umbHttpClient.get({ + url: '/umbraco/management/api/v1/server/status' +}); + +if (data) { + console.log('Server status:', data); +} +``` + +The above example shows how to use the Umbraco HTTP client to make a GET request to the Management API. The `umbHttpClient` object provides methods for making requests, including `get`, `post`, `put`, and `delete`. Each method accepts an options object with the URL, headers, and body of the request. + +The Umbraco HTTP client automatically handles authentication and error handling, so you don't have to worry about those details. It also provides a convenient way to parse the response data as JSON. + +## Using the Umbraco HTTP Client + +The Umbraco HTTP client is a wrapper around the Fetch API that provides a more convenient way to make network requests. It handles request and response parsing, error handling, and retries. The Umbraco HTTP client is available through the `@umbraco-cms/backoffice/http-client` package, which is included in the Umbraco Backoffice. You can use it to make requests to any endpoint in the Management API or to any other API. + +The recommended way to use the Umbraco HTTP Client is with the `tryExecute` function. This function handles any errors that occur during the request and automatically refreshes the token if it has expired. If the session has expired, it prompts the user to log in again. + +You can read more about the `tryExecute` function in this article: + +{% content-ref url="try-execute.md" %} +[try-execute.md](try-execute.md) +{% endcontent-ref %} + +## Generating a Custom Client + +You can also generate your own client using the `@hey-api/openapi-ts` library. This library allows you to generate a TypeScript client from an OpenAPI specification. The generated client will handle authentication and error handling for you, so you don't have to worry about those details. + +Read more about generating your own client here: + +{% content-ref url="custom-generated-client.md" %} +[custom-generated-client.md](custom-generated-client.md) +{% endcontent-ref %} + +## Further reading + +* [@hey-api/openapi-ts](https://heyapi.dev/openapi-ts/get-started) +* [@umbraco-cms/backoffice/http-client](https://apidocs.umbraco.com/v16/ui-api/modules/packages_core_http-client.html) +* [Using the Fetch API](fetch-api.md) +* [Creating a Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) diff --git a/17/umbraco-cms/customizing/foundation/fetching-data/try-execute.md b/17/umbraco-cms/customizing/foundation/fetching-data/try-execute.md new file mode 100644 index 00000000000..ee4f3bd3238 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/fetching-data/try-execute.md @@ -0,0 +1,64 @@ +--- +description:: Learn how to execute requests in the Backoffice. +--- + +# Executing Requests + +Requests can be made using the Fetch API or the Umbraco HTTP client. The Backoffice also provides a `tryExecute` function that you can use to execute requests. This function handles any errors that occur during the request and automatically refreshes the token if it has expired. If the session has expired, it prompts the user to log in again. + +{% hint style="info" %} +You can read the technical documentation for the `tryExecute` function in the [UI API Documentation](https://apidocs.umbraco.com/v16/ui-api/functions/packages_core_resources.tryExecute.html) class. +{% endhint %} + +## Using the Umbraco HTTP Client + +Here is an example of how to use the `tryExecute` function with the Umbraco HTTP client: + +```javascript +import { tryExecute } from '@umbraco-cms/backoffice/resources'; +import { umbHttpClient } from '@umbraco-cms/backoffice/http-client'; + +const { data, error } = await tryExecute(this, umbHttpClient.get({ + url: '/umbraco/management/api/v1/server/status' +})); + +if (error) { + console.error('There was a problem with the fetch operation:', error); +} else { + console.log(data); // Do something with the data +} +``` + +The `tryExecute` function takes the context of the current class or element as the first argument and the request as the second argument. Therefore, the above example can be used in any class or element that extends from either the [UmbController](https://apidocs.umbraco.com/v16/ui-api/interfaces/libs_controller-api.UmbController.html) or [UmbLitElement](https://apidocs.umbraco.com/v16/ui-api/classes/packages_core_lit-element.UmbLitElement.html) classes. + +{% hint style="info" %} +The above example requires a host element illustrated by the use of `this`. This is typically a custom element that extends the `UmbLitElement` class. +{% endhint %} + +It is recommended to always use the `tryExecute` function to wrap HTTP requests. It simplifies error handling, manages token expiration, and ensures a consistent user experience in the Backoffice. + +### Disabling Notifications + +The `tryExecute` function will automatically show error bubbles if a request fails. There may be valid cases where you want to handle errors yourself. This could, for instance, be if you want to show a custom error message. You can disable the notifications by passing the `disableNotifications` option to the `tryExecute` function: + +```javascript +tryExecute(this, request, { + disableNotifications: true, +}); +``` + +### Cancelling Requests + +The `tryExecute` function also supports cancelling requests. This is useful in scenarios where a request is taking too long, or the user navigates away from the page before the request completes. You can cancel a request by using the [AbortController API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). The `AbortController` API is a built-in API in modern browsers that allows you to cancel requests. You can use it directly with tryExecute: + +```javascript +const abortController = new AbortController(); + +// Cancel the request before starting it for illustration purposes +abortController.abort(); + +tryExecute(this, request, { + disableNotifications: true, + abortSignal: abortController.signal, +}); +``` diff --git a/17/umbraco-cms/customizing/foundation/icons.md b/17/umbraco-cms/customizing/foundation/icons.md new file mode 100644 index 00000000000..c6dc02f6fe8 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/icons.md @@ -0,0 +1,9 @@ +# Icons + +The icons in the Umbraco backoffice are based on [Lucide Icons](https://lucide.dev/) and [Simple Icons](https://simpleicons.org/). The syntax for using an icon starts with `icon-`. You can find the full list of available icons in the [All Icons article in the UI documentation](https://apidocs.umbraco.com/v16/ui/?path=/docs/umb-icons--docs). + +## Example + +```html + +``` diff --git a/17/umbraco-cms/customizing/foundation/integrate-validation.md b/17/umbraco-cms/customizing/foundation/integrate-validation.md new file mode 100644 index 00000000000..2b960b020cb --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/integrate-validation.md @@ -0,0 +1,88 @@ +--- +description: >- + Learn how to bind and use the validation system when working with Form + Controls and Umbraco CMS backoffice. +--- + +# Integrate Validation + +The Validation System provides abilities to validate different Form Controls. Such can be native or custom, like a Property Editor. + +It also allows for binding server validation to the Form Controls making the validation experience as synergetic as possible. + +## Validation Context + +Validation Context, the hub of the Validation, is the core of this system. Everything that holds opinions about the Validation, is a Validator and is connected to the Validation Context. + +You can ask the Validation Context to validate. This will evaluate all validators, and once all validator instances have been validated successfully, the Validation Context will be valid. + +## Validators + +We provide a few built-in Validators that handle most cases. + +### Form Control Validator + +This Validator binds a Form Control Element with the Validation Context. When the Form Control becomes Invalid, its Validation Message is appended to the Validation Context. + +Notice this one also comes as a Lit Directive called `umbBindToValidation`. This enables you to integrate an element with one line of code within a Lit Render method. See the following example for a demonstration: + +```typescript + +#validation = new UmbValidationContext(this); + +#validate = () => { + this.#validation.validate().then(() => { + console.log('Valid'); + }, () => { + console.log('Invalid'); + }); +} + +render() { + return html` + + + + Validate + `; +} +``` + +## Integrate Umb-Property Elements + +The `umb-property` element automatically binds to its nearest validation context. + +This is demonstrated in the example below: + +```typescript + +#validation = new UmbValidationContext(this); + +#validate = () => { + this.#validation.validate().then(() => { + console.log('Valid'); + }, () => { + console.log('Invalid'); + }); +} + +render() { + return html` + + + Validate + `; +} +``` + +## Server Validation and more + +This documentation is not available at the moment. For the moment you can find more information in the [Backoffice repository](https://github.com/umbraco/Umbraco-CMS/tree/ced3db8542d390bb12082ca63ef71b790da220c5/src/Umbraco.Web.UI.Client/src/packages/core/validation). diff --git a/17/umbraco-cms/customizing/foundation/lit-element.md b/17/umbraco-cms/customizing/foundation/lit-element.md new file mode 100644 index 00000000000..9773e41565a --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/lit-element.md @@ -0,0 +1,104 @@ +--- +description: >- + Backoffice supports any native Web Components. But we choose to use a little + framework to make it simpler. +--- + +# Lit Element + +Since a small framework is chosen to build the Web Components, it is recommended to consider doing the same. There are no strict requirements for how to build your components. However, most of the code and documentation examples are based on Lit. That said, many users successfully use other frameworks as well. + +To help you get started, here’s an overview of some relevant Lit features. + +## Render HTML + +To decide the content of your Element, you define a \`render\` method. It could look like this: + +```typescript +render() { + return html`The Rabbit went down a bold hole`; +} +``` + +## Bring Styles + +Declare a static styles property with the CSS Declarations you want for your Component. + +{% hint style="info" %} +The Element uses Shadow DOM, meaning the styles apply only to the content of your Element. Nothing more, not even other Web Components integrated inside your Component +{% endhint %} + +```typescript +static styles = [ + css` + b { + border-bottom: 2px solid var(--uui-color-divider); + } + `, +]; +``` + +## Reactive Properties + +Once your Element has some Data to represent, you most likely want to re-render the contents of your element when the data changes. + +To enable this, you can decorate the Properties that should be reactive with either \`@property\` or \`@state\`; the difference between these two is whether it's a Public property (@property) or a protected property (@state). + +```typescript +@customElement('name-of-example-component') +export class NameOfExampleComponent extends UmbLitElement { + + @property({ type: String }) + public name?: string + + render() { + return html`The Rabbit has a name ${this.name}`; + } +} +``` + +The Web Component above can then be used like this: + +```html + +``` + +## Parse value as JS properties + +You might want to parse data directly to an element within the render method. The following example shows how to parse a complex object into another Web Component without it being parsed via the DOM. This can be done by setting it directly as a JavaScript property: + +```typescript +#myComplexValue = { myString: "hey", myNumber: 123 } + +override render() { + return html` + + `; +} +``` + +Notice the `.` in front of the property name (`myValue`) + +## Listen to DOM Events + +You may like to listen to an event on one of the elements created via the render method. Luckily Lit enables you to do this. The following example shows how to assign an event listener to the 'click' event. + +```typescript + #onClick() { + console.log("I got clicked") + } + + override render() { + return html` + + `; + } +``` + +## Learn more + +To explore more features, visit the [Lit documentation](https://lit.dev/). + +{% hint style="warning" %} +It is recommended to use Lit for writing Web Components. It is not recommended to use Lit Controllers or the Lit Context API, as the Backoffice has its own APIs for those use cases. +{% endhint %} diff --git a/17/umbraco-cms/customizing/foundation/localization.md b/17/umbraco-cms/customizing/foundation/localization.md new file mode 100644 index 00000000000..8a202be75a1 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/localization.md @@ -0,0 +1,193 @@ +--- +description: Learn how to manage and use the Backoffice UI Localization files. +--- + +# Backoffice Localization + +This article describes how you can translate the Umbraco Backoffice UI into different languages. You can use the existing localizations from Umbraco or register your own localizations. You can also use the localization in your custom elements and controllers. + +## Registering Localization + +Localizations can be registered via the Extension Registry. [Read more about the Localization Extension Type](../extending-overview/extension-types/localization.md). + +### Missing Localization Keys + +As Umbraco is an evolving product, new text is regularly added to the English version of these files. Therefore, some of the languages may no longer be up-to-date. + +If a key is not found in the current language, the fallback language will be used. The fallback language is **English** with the culture code **en**. + +If a translation is missing, the default value within `umb-localize` will be shown in the user interface: + +```html +Default value +``` + +Instead of showing the default value we can show the key alias if we set `debug="true"`: + +```html + +``` + +## Using the Localizations + +### Localize Element + +The following example shows how you can display localized text with the `umb-localize` element: + +```html + +``` + +{% hint style="info" %} +You can have a look and try out the element in the [UI API Documentation](https://apidocs.umbraco.com/v15/ui/?path=/docs/api-localization-umblocalizeelement--docs). +{% endhint %} + +### **Localize Controller** + +In some situations, you need the localization as a variable that can be parsed. In this case, the Localization Controller can be used in your `element.ts` file. This can be setup in two ways: + +* Using [Umbraco Element](localization.md#umbraco-element) +* Using [Umbraco Controller](localization.md#umbraco-controller) + +#### Umbraco Element + +When using an [**Umbraco Element**](umbraco-element/)**,** the **Localization Controller** is already initialized on the `localize` property via the `UmbElementMixin`. + +```typescript +import { LitElement, css, html } from "lit"; +import { customElement } from "@umbraco-cms/backoffice/external/lit"; +import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; + +export default class MyElement extends UmbElementMixin(LitElement) { + render() { + return html` + `; + } +} +``` + +The arguments will be passed to the function in the localization file if it is a function. + +#### Umbraco Controller + +If you are working with an Umbraco Controller, then you need to initialize the Localization Controller on your own via the `UmbLocalizationController`: + +```typescript +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api'; + +export class MyController extends UmbControllerBase { + // Create a new instance of the controller and attach it to the element + #localize = new UmbLocalizationController(this); + + render() { + return html` `; + } +} +``` + +## Using arguments + +Sometimes you need to pass arguments to the localization to return different values based on the arguments. A localization value can be either a string or a function. Given a localization file like this, we can return different values based on the number of items: + +```javascript +export default { + section: { + numberOfItems: (count) => { + count = parseInt(count, 10); + if (count === 0) return 'Showing nothing'; + if (count === 1) return 'Showing only one item'; + return `Showing ${count} items`; + }, + }, +}; +``` + +{% hint style="info" %} +You can try out the arguments feature in the [UI API Documentation](https://apidocs.umbraco.com/v15/ui/?path=/story/api-localization-umblocalizeelement--with-arguments). +{% endhint %} + +**Using the Localize Element** + +You can pass arguments to the localization by adding them as additional attributes: + +```html + +Showing items +``` + +The arguments will be passed to the function in the localization file if it is a function. The `args` attribute must be JSON-serializable and each array value will be passed to the function as an extra argument. + +**Using the Localize Controller** + +You can pass arguments to the localization by calling the `term` method with the arguments: + +```typescript +// Outputs: Showing 5 items +this.localize.term('section_numberOfItems', 5); +``` + +The arguments will be passed to the function in the localization file if it is a function. Each argument of `term` will be passed to the function as an extra argument. + +### Using placeholders + +You can also use placeholders in the localization keys to replace parts of the string with dynamic values. Placeholders are defined by curly braces `{0}` or percentage signs `%0%` in the localization key. The placeholders will be replaced one-to-one with the arguments passed to the localization. It works the same as the arguments feature, except you cannot calculate the value based on the arguments. + +Given a localization file like this: + +{% code title="en.js" %} +```javascript +export default { + section: { + numberOfItems: 'Showing {0} items', + }, +}; +``` +{% endcode %} + +You can use the same `args` attribute to pass the arguments: + +```html + + +``` + +### Using with manifests + +You can localize values in a manifest. For example, prefix the name of the dashboard tab visible in the UI with a `#`. + +#### Example + +A manifest registering a dashboard with `umbraco-package.json` or JavaScript can localize the `label` property in the `meta` object like this. + +{% code title="umbraco-package.json" lineNumbers="true" %} +```json +{ + "name": "My.WelcomePackage", + "extensions": [ + { + "type": "dashboard", + ... + "meta": { + "label": "#welcomeDashboard_label", + "pathname": "welcome-dashboard" + }, + }, + ] +} +``` +{% endcode %} + +## Examples + +You can add your own localization keys using the principles you have learned, and apply them in a number of ways: + +### Using localization in a custom element + +You can find a localization example in the [Adding localization to the dashboard](../../tutorials/creating-a-custom-dashboard/adding-localization-to-the-dashboard.md) article. This will get you started with using localization in your custom elements. You can apply the same principles to all extensions. + +### Using localization in property descriptions and labels + +Property descriptions and labels can also be localized. They are formatted as Markdown and can contain localization keys using the built-in [Umbraco Flavored Markdown](../../reference/umbraco-flavored-markdown.md) syntax. diff --git a/17/umbraco-cms/customizing/foundation/repositories.md b/17/umbraco-cms/customizing/foundation/repositories.md new file mode 100644 index 00000000000..60669a85789 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/repositories.md @@ -0,0 +1,31 @@ +# Repositories + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A repository serves as the Backoffices entry point for requesting data and getting notified about updates. Each domain should register its own repository in the Backoffice. + +### Register a Repository + +```typescript +import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; +import { MyRepository } from './MyRepository'; + +const repositoryManifest = { + type: 'repository', + alias: 'My.Repository', + name: 'My Repository', + api: MyRepository, +}; +``` + +Repositories can use different data sources depending on the state of the application. The data sources can come from places like a server, an offline database, a store, or a Signal-R connection. That means that the consumer will not have to be concerned how to access the data, add or remove items from a collection, etc. This means we get a loose connection between the consumer and the data-storing procedures, hiding all complex implementation. + +### Data flow with a repository + +

Data flow

+ +A repository must be instantiated in the context where it is used. It should take a host element as part of the constructor. This ensures that any contexts consumed in the repository, like notifications or modals, are rendered in the correct DOM context. + +A repository can be called directly from an element, but will often be instantiated in a context, like the Workspace Context. diff --git a/17/umbraco-cms/customizing/foundation/routes.md b/17/umbraco-cms/customizing/foundation/routes.md new file mode 100644 index 00000000000..6f35d203a36 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/routes.md @@ -0,0 +1,72 @@ +--- +description: Get started with Routing in the backoffice. +--- + +# Routes + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +## Routing + +The routing in the backoffice is flexible and customizable. In this article, you can find a couple of starting points for routing. + +The overall **divider** is the [Section](../extending-overview/extension-types/sections/) which is a `ManifestSection` extension type. It is also used internally by the following sections: Content, Media, Settings, Members, and so on. + +Depending on which section you are working on, there are different options: + +* **SectionView**: The [Section View](../extending-overview/extension-types/sections/section-view.md) is a view in a section and one of the automatic router extension types. It can be an entry point to a section. If a section has multiple views defined (or both dashboards and views) then the tabs and icons will be rendered. As some examples, you can check the **Packages** and **Member** sections. +* **Dashboard**: The [Dashboard](../extending-overview/extension-types/dashboard.md) is an entry point to a section. If there is more than one section view or dashboard then the defined tabs and icons will be rendered to make it possible to navigate. +* **Workspace**: The [Workspace](../workspaces.md) concept has built-in features to facilitate editing of an entity of a certain entity type. It is used by many entities in the backoffice like content, media, content types, data types, dictionaries and so on. +* **Custom element**: A [Custom Element](umbraco-element/) is a section that can be configured to use any web component as the **entry point**. The `element()` can be configured in the manifest. By doing this we'll disable the possibility of using dashboards and section views for the section since they will not be automatically routed/rendered. This option should be used only when necessary. + +### Building routing + +Almost any component can host routable sub-components by defining a list of routes and render a `umb-router-slot` element. Let's assume we have a **custom section** with pathname `custom-section` and a **section view** with pathname `organization`. In this context we can create an element with routes, like this: + +```typescript +@state() +_routes: UmbRoute[] = [ + { + // Adding :personId as a parameter + path: 'person/:personId', + component: () => import('./person.element.js'), + setup: (_component, info) => { + + console.log('personId:',info.match.params.personId); + }, + }, + { + path: 'people', + component: () => import('./people.element.js'), + setup: (_component, info) => { + + console.log('view-route-info',info); + + }, + }, + { + path: '', + redirectTo: 'people', + }, +]; +``` + +{% hint style="info" %} +The order in which the routes are defined is important as the first match will be used. So make sure to add more specific routes in the beginning. +{% endhint %} + +In the render method of the element, render the `umb-router-slot`: + +```html + +``` + +One can create links to allow navigation to a given route: + +```html +People +Person 1 +Person 2 +``` diff --git a/17/umbraco-cms/customizing/foundation/sorting.md b/17/umbraco-cms/customizing/foundation/sorting.md new file mode 100644 index 00000000000..1e7449deeee --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/sorting.md @@ -0,0 +1,96 @@ +--- +description: Enable sorting elements via drag and drop +--- + +# Sorting + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The Umbraco Sorter enables you to make a list of elements sortable via drag-and-drop interaction. You have to set up the sorter once on the Element that renders the items to be sorted. As part of the configuration, you shall provide an `onChange` callback method, which will be executed every time the sorter makes a difference to the data. + +### Configuration + +The following example shows a basic setup of the Sorter. + +```typescript + +type ModelEntryType = { + id: string; + name: string; +} + +this.#sorter = new UmbSorterController(this, { + itemSelector: '.sorter-item', + containerSelector: '.sorter-container', + getUniqueOfElement: (element) => { + return element.getAttribute('data-sorter-id'); + }, + getUniqueOfModel: (modelEntry) => { + return modelEntry.id; + }, + onChange: ({ model }) => { + const oldValue = this._items; + this._items = model; + this.requestUpdate('_items', oldValue); + }, +}); +``` + +The properties provided are the following: + +* `itemSelector`: A query selector that matches the items that should be draggable. +* `containerSelector`: A query elector that matches the parent element of the items. +* `getUniqueOfElement`: A method that returns the unique element +* `getUniqueOfModel`: Provide a method that returns the unique of a given model entry +* `onChange`: Provide a method to retrieve the changed model. This is called every time the model is changed, including when the user is dragging around. + +### Data Model + +The model given to the Sorter must be an Array. The following example extends the example from above: + +```typescript + + const model: Array = [ + { + id: 1, + name: 'First item' + }, + { + id: 2, + name: 'second item' + } + { + id: 3, + name: 'Third item' + } + ] + + // Set the Model, if you have changes to the model not coming from the Sorter. Then set the model again: + this.#sorter.setModel(model); +``` + +### Rendering + +The Sorter does not move elements, instead, it updates the model as the user drags an item around. This puts higher pressure on the rendering of the sortable Elements. This means we need to make sure that the rendering re-uses the same element despite sorting the data differently. + +Lit does provide a render helper method called `repeat` that does this for us. The following example shows a render method that continues the work of the examples above: + +```typescript + + + render() { + return html` + + ${repeat( + this._items, + (item) => item.id, + (item) => + html`${item.name} + `, + )} + + `; + } +``` diff --git a/17/umbraco-cms/customizing/foundation/states.md b/17/umbraco-cms/customizing/foundation/states.md new file mode 100644 index 00000000000..3df43aebdef --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/states.md @@ -0,0 +1,133 @@ +--- +description: >- + Make reactivity with Umbraco States, enabling you to provide a value that + multiple others can observe and thereby be updated when the value changes. +--- + +# States + +An Umbraco State is a container for a value, it enables you to create [Observables](states.md#observables), which is the name of a hook into the States value — An Observable can then be Observed, such observation provides the current value and if the value of the State changes they will all be updated accordingly. + +A typical use case is when you need to implement reactivity across class instances. For example, a State is in a Context and the Observer is a Element. For a concrete example, see the [Extension Type Workspace Context](../extending-overview/extension-types/workspaces/workspace-context.md) article. + +{% hint style="info" %} +Umbraco States are not relevant when dealing with the reactivity of a Web Component. For that, see the [Lit Element](lit-element.md) article. +{% endhint %} + +The example below demonstrates the basics of working with a State and observing its changes: + +``` +const myState = UmbStringState('the initial value'); +const myObservable = myState.asObservable(); + +this.observe(myObservable, (value) => { + console.log(value); +}); + +myState.setValue('updated value'); +``` + +This example will result in the following logs: + +
> 'the initial value'
+> 'updated value'
+
+ +## State Types + +Umbraco provides built-in State types for common data structures: + +* Array State +* Boolean State +* Class State +* Number State +* Object State +* String State + +Use the one fitting for your value type. + +## Observe + +### Observe a state via Umbraco Element or Umbraco Controller + +The Umbraco Element or Controllers come with the ability to observe an Observable. + +Observing all changes will result in the callback being executed. + +The example below creates a State and then turns the whole state into an Observable, which then can be observed. + +
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
+
+...
+
+this.#selectionState = UmbArrayState<string>(['item1', 'item2']);
+this.selection = this.#selectionState.asObservable();
+
+this.observe(
+	this.selection,
+	(selection) => {
+		// This call will be executed initially and on each change of the state
+	}
+);
+
+ +### Change the value of a state + +The value of a state can be changed via the `setValue` method. This replaces the current data with new data. + +The following example shows how to change the value of the state to hold `item2` and `item3`. As the example extends the example from above, it means that `item1` is no longer part of the value of this state. + +
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
+
+...
+
+this.#selectionState.setValue(['item2', 'item3']);
+
+
+ +**Observe part of a state** + +With the `asObservablePart` method, you can set up an Observable that provides a transformed outcome, based on the State. + +```typescript +this.selectionLength = this.#selectionState.asObservablePart(data => data.length); + +this.observe( + this.selectionLength, (length) => { + // This call will be executed initially and on each change of the specific value that this observer provides. + // This means that this will only be executed when the length changes. Not if the value was replaced with a new value with the exact same length. + console.log("Length of selection is now ", length) + } +); +``` + +In the above example, the `asObservablePart` mapping function will be executed every time there is a change to the State. If the result of the method is different than before, it will trigger an update to its observers. + +Let's return to the example at the start of this article, to see how an observablePart is triggered in relation to the value of the state. + +``` +const myState = UmbStringState('four'); +const myObservable = myState.asObservable(); +const myObservablePart = myState.asObservablePart((value) => value.length); + +this.observe(myObservable, (value) => { + console.log("value:", value); +}); +this.observe(myObservablePart, (value) => { + console.log("length: ", value); +}); + +myState.setValue('five'); +myState.setValue('six');// notice only 3 letters +``` + +This example will result in the following logs: + +
> value: 'four'
+> length: 4
+> value: 'five'
+> value: 'six'
+> length: 3
+
+ +The `length` observation only got triggered when the length actually differed. diff --git a/17/umbraco-cms/customizing/foundation/terminology.md b/17/umbraco-cms/customizing/foundation/terminology.md new file mode 100644 index 00000000000..fa80eaf2626 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/terminology.md @@ -0,0 +1,22 @@ +--- +description: A list of some of the key concepts with working the Umbraco Backoffice. +--- + +# Terminology + +Understanding certain key concepts is essential when customizing the backoffice. These terminologies can help you decode the purpose of code effectively: + +* **Repository:** An API that enables communication with a server. +* **State:** A reactive container holding data, when data is changed, all its Observables will be notified. You can read more about states and observables in the [States](states.md) article. + * **Observable:** An observable is the hook for others to subscribe to the data of a State. + * **Observe:** Observe describes what we do when subscribing to an Observable. +* **Context-API:** The name used to serve APIs (instances/classes) for a certain context in the DOM. An API that is served via the Context-API is called a Context. You can read more about this in the [Context API](context-api/) article. + * **Context Provider:** Enables providing a class instance as a Context API. + * **Context Consumer:** Enables the consumption of a Context API. +* **Controller:** An abstract term for a thing that hooks into the lifecycle of an element. Many things in our system are Controllers. +* **Umbraco Controller:** Enables hosting controllers. Additionally, it provides a few shortcut methods for initializing core Umbraco Controllers. You can read more about this in the [Umbraco Controllers](umbraco-controller/) article. + * **Controller Host:** A class that can host controllers. + * **Controller Host Element:** The element that can host controllers. +* **Umbraco Element:** The `UmbLitElement` or `UmbElementMixin` enables hosting controllers. Additionally, it provides a few shortcut methods for initializing core Umbraco Controllers. You can read more about this in the [Umbraco Element](umbraco-element/) article. + +Read more about how to get started with extending the backoffice in the [Backoffice Setup](../extending-overview/) article. diff --git a/17/umbraco-cms/customizing/foundation/umbraco-controller/README.md b/17/umbraco-cms/customizing/foundation/umbraco-controller/README.md new file mode 100644 index 00000000000..9d06e2753d2 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/umbraco-controller/README.md @@ -0,0 +1,86 @@ +--- +description: >- + Contain or reuse logic across Elements. A Controller enables you to separate + logic while still being connected with the life cycle of an element. +--- + +# Umbraco Controller + +An Umbraco controller provides all the features of an Umbraco element within a separate class. Do this for architectural reasons or to reuse a feature across elements. + +## Host Element + +A Controller is assigned to a Host Element. This assignment may be indirect, since Controllers can host other Controllers. + +The host element is a web component enhanced to host controllers. All [Umbraco Elements](../umbraco-element/) are controller hosts, as are all Umbraco controllers, allowing controllers to host other controllers. + +To retrieve the controller’s host element, use the `getHostElement()` method. + +## Element Life Cycle + +Controllers can declare the following methods, which are triggered depending on the host element’s life cycle: + +* `hostConnected()` — Called when the host element connects to the DOM. +* `hostDisconnected()` — Called when the host element disconnects from the DOM. +* `destroy()` — Called when the controller is taken out of commission. + +Additionally, Umbraco Controllers implement a `getHostElement()` method, which enables any Controller to receive the Element that hosts the Controllers. + +## Registration + +A Controller should register itself with a given host. This is handled automatically when extending the `UmbControllerBase` class. The following example demonstrates a controller implementation: + +
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
+import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
+
+export class MyOwnControllerImplementation extends UmbControllerBase {
+
+    #secondsAlive = 0;
+
+    constructor(host: UmbControllerHost) {
+        // Parse the host to the base class, this will trigger the registration.
+        super(host);
+    }
+    
+    hostConnected() {
+        // It's important to call the super method when overriding a method of the base class.
+        super.hostConnected();
+        this.#timer = setInterval(this.#onInterval, 1000)
+    }
+    
+    hostDisconnected() {
+        // It's important to call the super method when overriding a method of the base class.
+        super.hostDisconnected();
+        clearInterval(this.#timer);
+    }
+    
+    #onInterval = () => {
+        this.#secondsAlive++;
+        console.log(`My own controller have been connected in ${this.#secondsAlive} seconds.`);
+    }
+
+    override destroy(): void {
+        // It's important to call the super method when overriding a method of the base class.
+        super.destroy();
+        // We do not need to stop the timer in the Destroy method, because the hostDisconnected method is also called if connected and destroyed.
+    }
+}
+
+ +If you don't like to extend the `UmbControllerBase`, then you can register a class as a controller as shown in the following example. Note that manual deregistration is required in this case. + +``` +export class MyOwnControllerImplementation { + + #host: UmbControllerHost; + + constructor(host: UmbControllerHost) { + this.#host = host; + this.#host.addUmbController(this); + } + + override destroy(): void { + this.#host.removeUmbController(this); + } +} +``` diff --git a/17/umbraco-cms/customizing/foundation/umbraco-element/README.md b/17/umbraco-cms/customizing/foundation/umbraco-element/README.md new file mode 100644 index 00000000000..a685f433980 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/umbraco-element/README.md @@ -0,0 +1,60 @@ +--- +description: Ease the integration with Backoffice by using a Umbraco Element +--- + +# Umbraco Element + +This provides a few methods to ease the connection with Backoffice, giving you the ability to: + +* Consume a Context — [Learn more about Consuming Contexts](../context-api/consume-a-context.md) +* Provide Context — [Learn more about Providing Contexts](../context-api/provide-a-context.md) +* Observe a State — [Learn more about States](../states.md#observe-a-state-via-umbraco-element-or-umbraco-controller) +* Use localization — [Learn more about Localization](../../../extending/language-files/) +* Host Controllers — [Learn more about Controllers](../umbraco-controller/) + +## Create an Umbraco Element + +You can turn any Web Component into an Umbraco Element by using the Umbraco Element Mixin, as done in the following example: + +```ts +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api' + +@customElement('my-extension-element') +class MyExtensionElement extends UmbElementMixin(HTMLElement) { + ... +} +``` + +This means you can use any base class, whether it’s a Web Component or a base class from your framework of choice. As long as it’s compatible with Web Components, it can be enhanced to become an Umbraco Element: + +
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'
+import { UUIButtonElement } from '@umbraco-cms/backoffice/external/uui'
+
+@customElement('my-extension-element')
+class MyExtensionElement extends UmbElementMixin(UUIButtonElement) {
+    ...
+}
+
+ +The Backoffice is generally built with Lit. To simplify things for those who prefer using the Lit version provided by the Backoffice, you can create your Web Components as Umbraco Elements like this: + +
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'
+
+@customElement('my-extension-element')
+export class MyExtensionElement extends UmbLitElement {
+    ...
+}
+
+ +Notice that it is identical to this: + +
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'
+import { LitElement } from '@umbraco-cms/backoffice/external/lit'
+
+@customElement('my-extension-element')
+class MyExtensionElement extends UmbElementMixin(LitElement) {
+    ...
+}
+
+ +Learn more about how to write Web Components with Lit in the [Lit Element article](../lit-element.md). diff --git a/17/umbraco-cms/customizing/foundation/umbraco-element/controllers/write-your-own-controller.md b/17/umbraco-cms/customizing/foundation/umbraco-element/controllers/write-your-own-controller.md new file mode 100644 index 00000000000..1c26304aec7 --- /dev/null +++ b/17/umbraco-cms/customizing/foundation/umbraco-element/controllers/write-your-own-controller.md @@ -0,0 +1,31 @@ +--- +description: Reuse functionality across components by writing it as a Controller +--- + +# Write your own controller + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A Controller must follow the interface of UmbController. To ease the implementation you can base your class on the `UmbControllerBase`: + +```typescript +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; + +class MyController extends UmbControllerBase { + + hostConnected() { + super.hostConnected(); + // Your code when the Host element is connected. + } + hostDisconnected() { + super.hostDisconnected(); + // Your code when the Host element is disconnected. + } + destroy() { + super.destroy(); + // Your code for when this controller gets destroyed. + } +} +``` diff --git a/17/umbraco-cms/customizing/overview.md b/17/umbraco-cms/customizing/overview.md new file mode 100644 index 00000000000..73922e0442d --- /dev/null +++ b/17/umbraco-cms/customizing/overview.md @@ -0,0 +1,29 @@ +--- +description: >- + Get an overview of the different options for UI customizing of the Umbraco CMS + backoffice. +--- + +# Overview + +The Backoffice is one of the core components of Umbraco CMS. It’s where content creators perform their daily work, and where projects are managed overall. + +{% hint style="info" %} +Are you looking to **extend and customize the Umbraco CMS**? + +Resources are available in the [Extending](../extending/build-on-umbraco-functionality.md) section for when you are looking to extend Umbraco functionality beyond the backoffice. +{% endhint %} + +In this section, you will find all the resources you need to customize or build an intuitive and fluid editor experience for your content editors. + +## General Resources + +
Extensions OverviewExplorer the various options for bringing your own piece into the platform.extending-overviewgitbook1.png
FoundationLearn about the Core features of the Backoffice, How you integrate and makes reactive UIfoundationgitbook1.png

Backoffice UI API

See what all of the modules export, interfaces, hierarchy, code examples, and much more.

https://apidocs.umbraco.com/v15/ui-api/index.htmlDocumentations Icons_Umbraco_CMS_Tutorials_the_Starter_Kit.png
Examples & PlaygroundExperience fully working customizations. This is also the place for you to get hands-on experience.examples-and-playground.mdDocumentations Icons_Umbraco_CMS_Reference_Querying_and_Models.png
+ +## Get started with a tutorial + +
Create a UI ExtensionGet started via this tutorial on how to extend the backoffice via a simple customizationcreating-your-first-extension.mdDocumentations Icons_Umbraco_CMS_Extending_Sections_and_Trees.png
Create a dashboardBring a good overview for the needs of your Content Editorscreating-a-custom-dashboardDocumentations Icons_Umbraco_CMS_Extending_Dashboards.png
Create a Property EditorBuild a custom editor for the needs of your Content Editorscreating-a-property-editorDocumentations Icons_Umbraco_CMS_Extending_Property_Editors.png
+ +*** + +{% include "../.gitbook/includes/umbraco-extending-the-backoffice-training-course.md" %} diff --git a/17/umbraco-cms/customizing/property-editors/README.md b/17/umbraco-cms/customizing/property-editors/README.md new file mode 100644 index 00000000000..9b99b738b0f --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/README.md @@ -0,0 +1,40 @@ +--- +description: Guide on how to work with and create Property Editors in Umbraco +--- + +# Property Editors + +{% hint style="info" %} +[This tutorial](../../tutorials/creating-a-property-editor/) contains step-by-step instructions for building a custom Property editor. +{% endhint %} + +{% hint style="warning" %} +The Property Editor articles are a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +This section describes how to work with and create Property Editors. A property editor is the editor used to insert content into Umbraco. [See here for definition](../../fundamentals/backoffice/property-editors/) + +## [Property Editors Composition](composition/) + +A property editor is an editor used to insert content into Umbraco. A Property Editor is composed of two extensions: Property Editor Schema and Property Editor UI. + +## [Package Manifest](../umbraco-package.md) + +Reference for the package.manifest JSON file format to register one or more property editors for Umbraco. + +## [Property Value Converters](property-value-converters.md) + +Convert the stored property data value to a useful object returned by the Published Content APIs. + +## [Property Actions](property-actions.md) + +Use Property Actions to add additional functionality to your custom property editors. + +## [Tracking References](tracking.md) + +Learn how to extend Property editors to track entity references inside the property editor. + +## More information + +* [Built in Property Editors](../../fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/) +* [Creating a property editor](../../tutorials/creating-a-property-editor/) diff --git a/17/umbraco-cms/customizing/property-editors/composition/README.md b/17/umbraco-cms/customizing/property-editors/composition/README.md new file mode 100644 index 00000000000..f0298a26a69 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/composition/README.md @@ -0,0 +1,24 @@ +--- +description: This section describes how to work with and create Property Editors. +--- + +# Property Editors Composition + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A property editor is an editor used to insert content into Umbraco. A Property Editor is composed of two extensions. To form a full Property Editor you will need a: + +* [Property Editor Schema](property-editor-schema.md) +* [Property Editor UI](property-editor-ui.md) + +A Property Editor UI is utilizing a Property Editor Schema, and you can have multiple Property Editor UIs for one Schema. This means you can find a Schema that solves your needs. You only need to build a Property Editor UI. + +* Each Property Editor can have multiple Property Editor UIs. +* Both a Property Editor Schema and Property Editor UI can define the Settings used for their configuration. + +### Configuration + +* Data Type Settings for a Property Editor or Property Editor UI is defined in the manifests. +* They both use the same format for their settings. diff --git a/17/umbraco-cms/customizing/property-editors/composition/property-editor-schema.md b/17/umbraco-cms/customizing/property-editors/composition/property-editor-schema.md new file mode 100644 index 00000000000..2b0d2728eda --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/composition/property-editor-schema.md @@ -0,0 +1,25 @@ +--- +description: The Server side part of a Property Editor +--- + +# Property Editor Schema + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The Property Editor Schema is server code, written in C#. This handles the storage of a Property Editor and defines _Server Side Validation_ and _Property Value Converters_. + +### Property Editor Schema + +The Property Editor Schema settings are used for configuration that the server needs to know about. + +**Manifest** + +```json +{ + "type": "propertyEditorSchema", + "name": "Text Box", + "alias": "Umbraco.TextBox", +}; +``` diff --git a/17/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md b/17/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md new file mode 100644 index 00000000000..b0b3c5c6624 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md @@ -0,0 +1,143 @@ +--- +description: Presenting the Editing Experience of a Property Editor +--- + +# Property Editor UI + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The Property Editor UI is the UI that is used to edit the data in the backoffice. + +The Property Editor UI is a pure front-end extension. This determines how the data of a Property Editor is presented and manipulated. The Extension points to a Web Component. + +### Property Editor UI + +{% code title="umbraco-package.json" %} +```json +{ + "type": "propertyEditorUi", + "alias": "Umb.PropertyEditorUi.TextBox", + "name": "Text Box Property Editor UI", + "element": "/App_Plugins/my-text-box/dist/my-text-box.js", + "elementName": "my-text-box", + "meta": { + "label": "My Text Box", + "propertyEditorSchemaAlias": "Umbraco.TextBox", + "icon": "icon-autofill", + "group": "common" + } +} +``` +{% endcode %} + +The Property Editor UI cannot be used for Content Types if no Property Editor Schema is specified in the manifest. However, it can still be utilized to manipulate JSON. A case of that could be a Settings property for another Property Editor UI or Schema. + +### Settings + +The Property Editor UI settings are used for configuration related to rendering the UI in the backoffice. This is the same for Property Editor Schemas: + +{% hint style="info" %} +The Property Editor UI inherits the Settings of its Property Editor Schema. +{% endhint %} + +**Manifest** + +{% code title="umbraco-package.json" %} +```json +{ + "type": "propertyEditorUi", + "alias": "My.PropertyEditorUI.TextArea", + //... more + "meta": { + //... more + "settings": { + "properties": [ + { + "alias": "rows", + "label": "Number of rows", + "description": "If empty - 10 rows would be set as the default value", + "propertyEditorUiAlias": "Umb.PropertyEditorUi.Integer", + }, + ], + "defaultData": [ + { + "alias": "rows", + "value": 10, + }, + ], + }, + }, +}; +``` +{% endcode %} + +## The Property Editor UI Element + +Implement the `UmbPropertyEditorUiElement` interface, to secure your Element live up to the requirements of this. + +```typescript +interface UmbPropertyEditorUiElement extends HTMLElement { + name?: string; + value?: unknown; + config?: UmbPropertyEditorConfigCollection; + mandatory?: boolean; + mandatoryMessage?: string; + destroy?: () => void; +} +``` + +{% hint style="info" %} +The `UmbPropertyEditorUiElement` interface ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. + +See the [UI API documentation](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. +{% endhint %} + +**Example with LitElement** + +{% code title="my-text-box.ts" lineNumbers="true" %} +```typescript +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, +} from '@umbraco-cms/backoffice/property-editor'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; + +@customElement('umb-property-editor-ui-text-box') +export default class UmbPropertyEditorUITextBoxElement extends UmbLitElement implements UmbPropertyEditorUiElement { + @property() + value?: string; + + @property({ attribute: false }) + config?: UmbPropertyEditorConfigCollection; + + #onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html``; + } + + static override readonly styles = [ + UmbTextStyles, + css` + uui-input { + width: 100%; + } + `, + ]; +} + +declare global { + interface HTMLElementTagNameMap { + 'umb-property-editor-ui-text-box': UmbPropertyEditorUITextBoxElement; + } +} +``` +{% endcode %} diff --git a/17/umbraco-cms/customizing/property-editors/full-examples-value-converters.md b/17/umbraco-cms/customizing/property-editors/full-examples-value-converters.md new file mode 100644 index 00000000000..774c4371e7f --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/full-examples-value-converters.md @@ -0,0 +1,67 @@ +# Property Value Converter full example +This page includes an example of a complete Property Value Converter. The example is that of a Property Value Converter for a Content Picker, where the user picks a node from the Umbraco tree. + + +{% code title="ContentPickerPropertyConverter.cs" %} + +```csharp +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PublishedCache; + +namespace UmbracoDocs.Samples; + +// Injecting the IPublishedContentCache for fetching content from the Umbraco cache +public class ContentPickerPropertyConverter(IPublishedContentCache publishedContentCache) : IPropertyValueConverter +{ + // Make sure the Property Value Converter only applies to the Content Picker property editor + public bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ContentPicker); + + + // We consider the value to be a value only when we have the actual IPublishedContent object, + // meaning that there is a valid picked content item. + public bool? IsValue(object? value, PropertyValueLevel level) + { + return level switch + { + PropertyValueLevel.Source => null, + PropertyValueLevel.Inter => null, + PropertyValueLevel.Object => value is IPublishedContent, + _ => throw new ArgumentOutOfRangeException(nameof(level), level, $"Invalid level: {level}.") + }; + } + + // The type returned by this converter is IPublishedContent + // And the Models Builder will take care of returning the actual generated type + public Type GetPropertyValueType(IPublishedPropertyType propertyType) + => typeof(IPublishedContent); + + // Because we have a reference to another content item, we need to use the Elements cache level, + // to make sure that changes to the referenced item are detected and the cache invalidated accordingly. + public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) + => PropertyCacheLevel.Elements; + + // Converts the source value (string) to an intermediate value (GuidUdi) + public object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, + object? source, bool preview) + { + if (source is not string { Length: > 0 } stringValue) + return null; + + return UdiParser.TryParse(stringValue, out GuidUdi? guidUdi) ? guidUdi : null; + } + + // Converts the intermediate value (GuidUdi) to the actual object value (IPublishedContent) + public object? ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, + PropertyCacheLevel referenceCacheLevel, object? inter, bool preview) + => inter is GuidUdi guidUdi + ? publishedContentCache.GetById(guidUdi.Guid) + : null; +} + + +``` + +{% endcode %} diff --git a/17/umbraco-cms/customizing/property-editors/images/JSON-schema.png b/17/umbraco-cms/customizing/property-editors/images/JSON-schema.png new file mode 100644 index 00000000000..70003504b6b Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/JSON-schema.png differ diff --git a/17/umbraco-cms/customizing/property-editors/images/data-types-references.png b/17/umbraco-cms/customizing/property-editors/images/data-types-references.png new file mode 100644 index 00000000000..d09a0db0f02 Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/data-types-references.png differ diff --git a/17/umbraco-cms/customizing/property-editors/images/document-references (1).png b/17/umbraco-cms/customizing/property-editors/images/document-references (1).png new file mode 100644 index 00000000000..504116f0e2a Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/document-references (1).png differ diff --git a/17/umbraco-cms/customizing/property-editors/images/document-references.png b/17/umbraco-cms/customizing/property-editors/images/document-references.png new file mode 100644 index 00000000000..504116f0e2a Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/document-references.png differ diff --git a/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions (1).jpg b/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions (1).jpg new file mode 100644 index 00000000000..2e94865f559 Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions (1).jpg differ diff --git a/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions.jpg b/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions.jpg new file mode 100644 index 00000000000..2e94865f559 Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/example-of-property-actions.jpg differ diff --git a/17/umbraco-cms/customizing/property-editors/images/media-references.png b/17/umbraco-cms/customizing/property-editors/images/media-references.png new file mode 100644 index 00000000000..504116f0e2a Binary files /dev/null and b/17/umbraco-cms/customizing/property-editors/images/media-references.png differ diff --git a/17/umbraco-cms/customizing/property-editors/integrate-property-editors.md b/17/umbraco-cms/customizing/property-editors/integrate-property-editors.md new file mode 100644 index 00000000000..30640fa5cda --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/integrate-property-editors.md @@ -0,0 +1,42 @@ +# Integrate Property Editors + +Property Editors can be used and implemented anywhere in the Umbraco Backoffice. + +## Property & Property Dataset Components + +The simplest way to integrate one or more Property Editors is done using two Components: the Property Dataset component and a Property component. + +The `umb-property` component renders a property using a Property Editor UI. + +The `umb-property-dataset` component provides the dataset for any properties within. It holds the data even if the actual property is not rendered. This makes it possible to hide properties in tabs or other ways. + +In the following example a dataset is implemented with two properties: + +```js + + + + +``` + +Notice how the values of the properties are handled by the dataset, leaving you with one component to integrate. + +[Read more about Property Dataset here](property-dataset.md) diff --git a/17/umbraco-cms/customizing/property-editors/property-actions.md b/17/umbraco-cms/customizing/property-editors/property-actions.md new file mode 100644 index 00000000000..e40d6b560b6 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/property-actions.md @@ -0,0 +1,111 @@ +--- +description: Guide on how to implement Property Actions for Property Editors in Umbraco +--- + +# Property Actions + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Property Actions are a built-in feature that provide a generic place for secondary functionality for property editors. + +Property Actions appear as a small button next to the label of the property, which expands to show the available actions. They are defined and implemented in the Property Editor, making it open as to what a Property Action is. + +## Data Structure of Property Actions + +Property Actions are an array of objects defining each action. An action is defined by the following properties: + +```js +{ + labelKey: 'clipboard_labelForRemoveAllEntries', + labelTokens: [], + icon: 'trash', + method: removeAllEntries, + isDisabled: true +} +``` + +We use `labelKey` and `labelTokens` to retrieve a localized string that is displayed as the Actions label. [See localization for more info.](../../extending/language-files/) + +`isDisabled` is used to disable an Action, which change the visual appearance and prevents interaction. Use this option when an action wouldn't provide any change. In the example above, the action `remove all entries` would not have any impact if there is no entries. + +## Implementation + +The implementation of Property Actions varies depending on whether your Property Editor is implemented with a Controller or as a Component. + +### Controller Implementation + +When your Property Editor is implemented with a Controller, use the following approach for the Property Action: + +```js +angular.module("umbraco").controller("My.MarkdownEditorController", function ($scope) { + +function myActionExecutionMethod() { + alert('My Custom Property Action Clicked'); + // Disable the action so it can not be re-run + // You may have custom logic to enable or disable the action + // Based on number of items selected etc... + myAction.isDisabled = true; +}; + +var myAction = { + labelKey: 'general_labelForMyAction', + labelTokens: [], + icon: 'action', + method: myActionExecutionMethod, + isDisabled: false +} + +var propertyActions = [ + myAction +]; + +this.$onInit = function () { + if ($scope.umbProperty) { + $scope.umbProperty.setPropertyActions(propertyActions); + } +}; + + +}); +``` + +### Component Implementation + +Follow this guide if your Property Editor is implemented as a Component. The Component must be configured to retrieve an optional reference to `umbProperty`. The requirement must be optional because property-editors are implemented in scenarios where it's not presented. + +See the following example: + +```js +angular.module('umbraco').component('myPropertyEditor', { + controller: MyController, + controllerAs: 'vm', + require: { + umbProperty: '?^umbProperty' + } + … +}); +``` + +See the following example for implementation of Property Actions in a Component, notice the difference is that we are parsing actions to `this.umbProperty.setPropertyActions(...)`. + +```js +var myAction = { + labelKey: 'general_labelForMyAction', + labelTokens: [], + icon: 'action', + method: myActionExecutionMethod, + isDisabled: false +} + +var propertyActions = [ + myAction +]; + +this.$onInit = function () { + if (this.umbProperty) { + this.umbProperty.setPropertyActions(propertyActions); + } +}; +``` diff --git a/17/umbraco-cms/customizing/property-editors/property-dataset.md b/17/umbraco-cms/customizing/property-editors/property-dataset.md new file mode 100644 index 00000000000..22685f41885 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/property-dataset.md @@ -0,0 +1,59 @@ +--- +description: >- + Looking to implement one or more Property Editors in your own scenario? The + Property Dataset is necessary for a Property Editor to work, so make sure to + have that integrated first. +--- + +# Property Dataset + +A Property Dataset is a Context API that holds the data for a set of properties. + +It is required for the `umb-property` element to have a Property Dataset provided. It can be provided via JavaScript code or an Element as documented below. + +## Property dataset component + +The `umb-property-dataset` component provides a Property Dataset Context for any properties within. This provides a way to implement such purely via Elements. + +In the following example a dataset is implemented by using the `umb-property-dataset` component together with with two `umb-property` components: + +```xml + + + + +``` + +## Consume values + +Since a Property Dataset is a Context any descending code can consume it and utilize the values. + +Such a case could be a Workspace View that wants to display the value of a specific property. + +The following example shows how to consume the Property Dataset and observe the value of a property with the alias of `my-property-alias`. + +```typescript +this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, async (datasetContext) => { + this.observe(await datasetContext?.propertyValueByAlias('my-property-alias'), (value) => { + console.log('the value of `my-property-alias` is', value) + }); +}); +``` diff --git a/17/umbraco-cms/customizing/property-editors/property-editor-validation.md b/17/umbraco-cms/customizing/property-editors/property-editor-validation.md new file mode 100644 index 00000000000..b78c8af6085 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/property-editor-validation.md @@ -0,0 +1,103 @@ +--- +description: >- + Looking to add Validation rules for your own Property Editor? This article + describes how to append validation rules to your Property Editor. +--- + +# Property Editor Validation + +Adding Validation rules to a Property Editor is the same as adding Validation Rules to any Web Component. But it does require that your Web Component be a Form Control. + +To achieve this, you can use a Mixin called `UmbFormControlMixin` . The following example shows how this could look: + +```typescript +import { customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; + +@customElement('my-property-editor') +export class MyPropertyEditorElement + extends UmbFormControlMixin(UmbLitElement) + implements UmbPropertyEditorUiElement { + + /** + Notice 'value'-property is already defined via the FormControlMixin, based on the first generic type given to it + */ + + ... + +} + +export default MyPropertyEditorElement; + +declare global { + interface HTMLElementTagNameMap { + 'my-property-editor': MyPropertyEditorElement; + } +} + +``` + +### Add Validation rules + +Once your Property Editor is a Form Control, you can append validation rules to it. + +```typescript +... + + constructor() { + super(); + + this.addValidator( + 'customError', + () => 'This field must contain a "Unicorn"', + () => !this.value.includes("unicorn"), + ); + } + +... +``` + +The first argument declares what type of validation error you are evaluating. You can see the various types that browsers support on the [Mozilla Development Docs](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState#instance_properties). + +The second argument is a method that returns the message; this message will be displayed if the Validator Check returns `true`. + +The third argument is the Validator check, which is executed every time there is a change in the properties of this Web Component. If it returns `true` , the component will turn invalid, and the messages of argument two will be used as feedback to the user. + +{% hint style="info" %} +If you're looking to make server requests as part of your check, then it is recommended to avoid calling the server more often than needed. Do only ask the server if there is a value, and only ask the server again if the value is different from last time. +{% endhint %} + +Notice that `value` is already defined in the FormControlMixin, and ideally, you do not overwrite it. If so, then please make sure to still set the value property of the Mixin. As that will trigger a validation update. + +```typescript + @property({ type: String }) + public override set value(value: string) { + // [ What you needed to do... ] + super.value = value; + } + public override get value() { + return super.value; + } +``` + +### Integrate the validation of an inner element + +You may have inner elements that are `FormControls` and should affect the validity of your property editor.\ +In this case, bind the inner element to the property editor. + +The following example shows how to make a local `uui-input` part of the property editor’s validation. + +```typescript +... + + protected override firstUpdated() { + this.addFormControlElement(this.shadowRoot!.querySelector('uui-input')!); + } + +... +``` + +{% hint style="info" %} +This example requires your property editor to be built with Lit. If you are not using Lit, you need another way to detect when the element is in the DOM or to create it virtually. +{% endhint %} diff --git a/17/umbraco-cms/customizing/property-editors/property-value-converters.md b/17/umbraco-cms/customizing/property-editors/property-value-converters.md new file mode 100644 index 00000000000..f64d7cb5cc3 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/property-value-converters.md @@ -0,0 +1,232 @@ +--- +description: A guide to creating a custom Property Value Converter in Umbraco +--- + +# Property Value Converters + +A Property Value Converter converts a property editor's database-stored value into another type that is stored in the Umbraco cache. This way, the database stores only essential data. Razor views, the Published Content API, and the Content Delivery API use strongly typed, cleaner models. + +For example, a Content Picker stores the Key of the picked node in the database. When reading published data, Umbraco returns an `IPublishedContent` object instead of the Key. This conversion is done by a Property Value Converter. + +A Property Value Converter has three conversion levels: +* **Source** - The raw data stored in the database; this is generally a `string`. +* **Intermediate** - An object of a type that is appropriate to the property. For example, a node Key should be a `Guid`, or a collection of node Keys would be a `Guid[]`. +* **Object** - The object to be used when accessing the property using the Published Content API. For example, the object returned by the `IPublishedContent.Value(alias)` method. Additionally, the Models Builder generates a property of the same type as the object. + +## Create a Property Value Converter +A class becomes a Property Value Converter when it implements the `IPropertyValueConverter` interface from the `Umbraco.Cms.Core.PropertyEditors` namespace. Property Value Converters are automatically registered when implementing the interface. Any given PropertyEditor can only utilize a single Property Value Converter. + +```csharp +public class ContentPickerValueConverter : IPropertyValueConverter +``` + +{% hint style="info" %} +Consider using the `PropertyValueConverterBase` class as the base of your Property Value Converter instead of the `IPropertyValueConverter` interface. The `PropertyValueConverterBase` class comes with a default implementation of `IPropertyValueConverter`, so you only have to override the methods you need to change. In contrast, if you use the `IPropertyValueConverter`, you are responsible for implementing all methods yourself. In this document, it is assumed that you are using the `IPropertyValueConverter`, so methods are covered. +{% endhint %} + +The `IPropertyValueConverter` interface exposes the following methods you need to implement: + +## Implement information methods +Implement the following methods, which provide Umbraco with context about the Property Value Converter. + +### `IsConverter(IPublishedPropertyType propertyType)` + +This method is called for each `PublishedPropertyType` (Document Type Property) at Umbraco startup. By returning `true`, your value converter will be registered for that property type. Umbraco then executes your conversion methods whenever that value is requested. + +Example: Checking if the `IPublishedPropertyType.EditorAlias` property is equal to the alias of the core content editor.\ +This check is a string comparison, but creating a constant is recommended to avoid spelling errors: + +```csharp +public bool IsConverter(IPublishedPropertyType propertyType) +{ + return propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ContentPicker); +} +``` + +### `IsValue(object value, PropertyValueLevel level)` +The `IsValue` method determines whether a property contains a meaningful value or should be considered "empty" at different stages of the value conversion process. This method is essential for Umbraco's `property.HasValue()` method. + +{% hint style="info" %} +There's a basic implementation of this method in `PropertyValueConverterBase` that's good enough for most scenarios. +{% endhint %} + +When Umbraco needs to check if a property has a valid value, it calls IsValue progressively through three conversion levels until one returns true. They are called in the order of Source > Inter > Object. This allows you to choose at what stage of the conversion you need to perform the validation to get the best results. Consider these scenarios: + +```csharp +//If value is a simple string, it's enough to just check if string is null or empty +//This is the default implementation in PropertyValueConverterBase +public bool? IsValue(object? value, PropertyValueLevel level) +{ + switch (level) + { + case PropertyValueLevel.Source: + return value != null && (!(value is string stringValue) || !string.IsNullOrWhiteSpace(stringValue)); + case PropertyValueLevel.Inter: + return null; + case PropertyValueLevel.Object: + return null; + default: + throw new NotSupportedException($"Invalid level: {level}."); + } +} + +//If the value is numeric, it's usually not enough to check if the raw string value is null +//or empty, but also to check if the value is a valid int and if it doesn't contain the default value +public bool? IsValue(object? value, PropertyValueLevel level) +{ + switch (level) + { + case PropertyValueLevel.Source: + return null; + case PropertyValueLevel.Inter: + return value is int intValue && intValue > 0; + case PropertyValueLevel.Object: + return null; + default: + throw new NotSupportedException($"Invalid level: {level}."); + } +} + +//If the value is a complex object, you can consider checking +//the object level +public bool? IsValue(object? value, PropertyValueLevel level) +{ + switch (level) + { + case PropertyValueLevel.Source: + return null; + case PropertyValueLevel.Inter: + return null; + case PropertyValueLevel.Object: + return value is ComplexObject objectValue && objectValue.SomeProperty == "value"; + default: + throw new NotSupportedException($"Invalid level: {level}."); + } +} +``` + +### `GetPropertyValueType(IPublishedPropertyType propertyType)` + +This is where you can specify the type returned by this converter. This type will be used by Models Builder to return data from properties using this converter in the proper type. + +Example: Content Picker data is being converted to `IPublishedContent`. + +```csharp +public Type GetPropertyValueType(IPublishedPropertyType propertyType) +{ + return typeof(IPublishedContent); +} +``` + +### `GetPropertyCacheLevel(IPublishedPropertyType propertyType)` + +Here you specify which level the property value is cached at. + +A property value can be cached at the following levels: + +#### `PropertyCacheLevel.Element` +This is the most commonly used cache level and should be your default, unless you have specific reasons to do otherwise. + +The property value will be cached until its _element_ is modified. The element is what holds (or owns) the property. For example: + +* For properties used at the page level, the element is the entire page. +* For properties contained within Block List items, the element is the individual Block List item. + +#### `PropertyCacheLevel.Elements` + +The property value will be cached until _any_ element (see above) is changed. This means that any change to any page will clear the property value cache. + +This is particularly useful for property values that contain references to other content or elements. For example, this cache level is utilized by the Content Picker to clear its property values from the cache upon content updates. + +#### `PropertyCacheLevel.None` + +The property value will _never_ be cached. Every time a property value is accessed (even within the same snapshot) property conversion is performed explicitly. + +{% hint style="danger" %} +Use this cache level with extreme caution, as it incurs a massive performance penalty. +{% endhint %} + +#### `PropertyCacheLevel.Unknown` + +Do not use this cache level as it is a default fallback for the `PropertyCacheLevel` enum. It will throw an error when used. + +```csharp +public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) +{ + return PropertyCacheLevel.Elements; +} +``` + +## Implement conversion methods +Implement the methods that perform the conversion from a raw database value to an intermediate value and then to the final type. Conversions happen in two steps. + +### `ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)` +This method converts the raw data value into an appropriate intermediate type that is needed for the final conversion step to an object. +For example: +- A basic text property likely stores its data as a `string`, so that can be converted to a `string` intermediate value. +- A Content Picker stores the node identifier (`Udi`) as a `string`. To return `IPublishedContent`, the final conversion step needs a `Udi` instead. So in the intermediate step, check if the `string` value is a valid `Udi` and convert the `string` to a `Udi` as the intermediate value. + +```csharp +// Basic text property example of intermediate conversion +public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) +{ + return source as string; +} +``` + +```csharp +// Converting the source value (string) to an intermediate value (GuidUdi) +public object? ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, + object? source, bool preview) +{ + if (source is not string { Length: > 0 } stringValue) + return null; + + return UdiParser.TryParse(stringValue, out GuidUdi? guidUdi) ? guidUdi : null; +} +``` + +### `ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)` + +This method converts the intermediate value to an object of the type specified in the `GetPropertyValueType()` method of the Property Value Converter. The returned value is used by the `GetPropertyValue` method of `IPublishedContent`. + +The example below converts the node `GuidUdi` into an `IPublishedContent` object. + +```csharp +// Converts the intermediate value (GuidUdi) to the actual object value (IPublishedContent) +public object? ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview) + => inter is GuidUdi guidUdi + ? publishedContentCache.GetById(guidUdi.Guid) + : null; +``` + +## Override existing Property Value Converters +To override an existing Property Value Converter, either from Umbraco or a package, additional steps are required. Deregister the existing one to prevent conflicts. + +```csharp +using System.Linq; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; + +public class MyComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + //If the type is accessible (not internal) you can deregister it by the type: + builder.PropertyValueConverters().Remove(); + + //If the type is not accessible you will need to locate the instance and then remove it: + var contentPickerValueConverter = builder.PropertyValueConverters().GetTypes() + .FirstOrDefault(converter => converter.Name == "ContentPickerValueConverter"); + + if (contentPickerValueConverter != null) + { + builder.PropertyValueConverters().Remove(contentPickerValueConverter); + } + } +} +``` + +## Full example + +[Content Picker to `IPublishedContent` using `IPropertyValueConverter` interface](full-examples-value-converters.md) diff --git a/17/umbraco-cms/customizing/property-editors/tracking.md b/17/umbraco-cms/customizing/property-editors/tracking.md new file mode 100644 index 00000000000..a476528d812 --- /dev/null +++ b/17/umbraco-cms/customizing/property-editors/tracking.md @@ -0,0 +1,95 @@ +--- +description: >- + Guide on how to implement tracking entity references for Property Editors in + Umbraco +--- + +# Tracking References + +Property editors can be extended further to track entity references that may be selected or referenced inside the property editor. For example in the core of the CMS we have added this to numerous property editors. + +A good example of this is the Media Picker. The CMS stores a reference to the selected media item, enabling the identification of content nodes that use that particular media item. This avoids it being accidentally deleted if it is being used. + +When a content node is saved it will save the entity references as relations. + +## Viewing References + +### For Media Items + +1. Go to the **Media** section. +2. Select a media item and click the **Info** tab. + +![Viewing media references](images/media-references.png) + +### For Content Nodes + +1. Go to the **Settings** section. +2. Under the **Relations** from the **Advanced** section, select **Related Document** relations. + +![Viewing document references](images/document-references.png) + +### For Data Types + +1. Go to the **Settings** section. +2. Expand the **Data Types** folder. +3. Select the **Data Type** you wish to view the references. +4. Navigate to the **Info** tab. + +![Viewing Data Type references](images/data-types-references.png) + +## Example + +The following example shows how to implement tracking for the inbuilt CMS property editor **Content Picker**. It will always add a specific media reference, regardless of what value is picked in the content picker. In your own implementations, you will need to parse the value stored from the property editor you are implementing. You will also need to find any references to picked items in order to track their references. + +{% code title="TrackingExample.cs" %} +```csharp +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Editors; +using Umbraco.Cms.Core.PropertyEditors; + +namespace UmbracoDocs.Samples; + +public class TrackingExample : IDataValueReferenceFactory, IDataValueReference +{ + public IDataValueReference GetDataValueReference() => this; + + // Which Data Editor (Data Type) does this apply to - in this example it is the built in content picker of Umbraco + public bool IsForEditor(IDataEditor? dataEditor) + => dataEditor?.Alias.InvariantEquals(Constants.PropertyEditors.Aliases.ContentPicker) is true; + + public IEnumerable GetReferences(object? value) + { + // Value contains the raw data that is being saved for a property editor + // You can then analyse this data be it a complex JSON structure or something more trivial + // To add the chosen entities as references (as any UDI type including custom ones) + + // A very simple example + // This will always ADD a specific media reference to the collection list + // When it's a ContentPicker datatype + var references = new List(); + var udiType = UmbracoObjectTypes.Media.GetUdiType(); + var udi = Udi.Create(udiType, Guid.Parse("fbbaa38d-bd93-48b9-b1d5-724c46b6693e")); + var entityRef = new UmbracoEntityReference(udi); + references.Add(entityRef); + return references; + } +} +``` +{% endcode %} + +You'll need a Composer to enable the tracking example: + +{% code title="TrackingExampleComposer.cs" %} +```csharp +using Umbraco.Cms.Core.Composing; + +namespace UmbracoDocs.Samples; + +public class TrackingExampleComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.DataValueReferenceFactories().Append(); +} +``` +{% endcode %} diff --git a/17/umbraco-cms/customizing/property-level-ui-permissions.md b/17/umbraco-cms/customizing/property-level-ui-permissions.md new file mode 100644 index 00000000000..2c385c1a233 --- /dev/null +++ b/17/umbraco-cms/customizing/property-level-ui-permissions.md @@ -0,0 +1,173 @@ +--- +description: >- + Use the UI Property Permissions to restrict access to specific properties in + the Backoffice UI. +--- + +# Property Level UI Permissions + +## Document Property Value User Permissions + +Umbraco provides a feature called Document Property Value User Permissions. This feature can restrict access to specific Document property values for certain user groups. By default, all the built-in User Groups have read and write permissions for all properties. However, you can limit a User Group's permissions for specific properties through the UI. + +If a User Group doesn't have write access to a property, the property will be read-only for that User Group. If a User Group doesn't have read access to a property, the property will be hidden from that User Group. + +{% hint style="info" %} +The Document Property Value User Permissions are not enforced on the server side. This means a user can still access the property value through the API, even if the property is restricted in the UI. +{% endhint %} + +## Write custom Property Level Permissions + +It is possible to manipulate the permissions via code. This can be achieved through the Guard Managers available on all Content-Type-based Workspace Contexts. + +These are the available guards: + +* `propertyViewGuard` - Manages rules for the visibility of properties. +* `propertyWriteGuard` - Manages rules for the writability of properties. +* `readOnlyGuard` (This will be removed in the future. Use `propertyWriteGuard` instead) + +The following guide demonstrates how to implement custom rules from a Workspace Context that appends rules to the Guard Managers. + +### Register a Workspace Context + +Register a [Workspace Context](https://github.com/madsrasmussen/UmbracoDocs/blob/180d6e9eb7ab722a24b7b209c71de03cbe811e00/15/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-context.md) to enable appending code to run when a workspace is initialized. + +**Manifest** + +{% code title="manifest.ts" %} +```typescript +import { UMB_WORKSPACE_CONDITION_ALIAS } from "@umbraco-cms/backoffice/workspace"; +import { UMB_DOCUMENT_WORKSPACE_ALIAS } from "@umbraco-cms/backoffice/document"; + +const manifest: UmbExtensionManifest = { + type: "workspaceContext", + name: "My Document Property Permission Workspace Context", + alias: "My.WorkspaceContext.DocumentPropertyPermission", + api: () => import("./my-document-property-permission.workspace-context.js"), + conditions: [ + { + alias: UMB_WORKSPACE_CONDITION_ALIAS, + match: UMB_DOCUMENT_WORKSPACE_ALIAS, + }, + ], +}; +``` +{% endcode %} + +### Write a general rule + +The following example adds code for the Workspace Context to set up a single rule preventing writing to all properties. + +**Workspace Context** + +{% code title="WorkspaceContext.ts" %} +```typescript +import { UmbControllerBase } from "@umbraco-cms/backoffice/class-api"; +import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/document"; +import { UmbVariantId } from "@umbraco-cms/backoffice/variant"; + +export class MyDocumentPropertyPermissionWorkspaceContext extends UmbControllerBase { + constructor(host: UmbControllerHost) { + super(host); + + // Consume the document workspace context + this.consumeContext( + UMB_DOCUMENT_WORKSPACE_CONTEXT, + (context) => { + + // Create a rule: + const rule = { + unique: 'myCustomRuleIdentifier', + permitted: false, + message: "None of these properties are writable because of my custom restriction.", + } + // Add the rule to the write guard + context?.propertyWriteGuard.addRule(rule); + } + ); + } +} + +export { MyDocumentPropertyPermissionWorkspaceContext as api }; +``` +{% endcode %} + +This showed how to append a general rule to all properties or variants. This can be made more specific. Therefore, the following example shows how to make a rule that applies to a specific property. + +### Write a rule for a specific property + +The following example adds code to retrieve the `unique` value for a given property. This is then used to create a rule that only prevents writing to that property. + +**Workspace Context** + +{% code title="WorkspaceContext.ts" %} +```typescript +import { UmbControllerBase } from "@umbraco-cms/backoffice/class-api"; +import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/document"; +import { UmbVariantId } from "@umbraco-cms/backoffice/variant"; + +export class MyDocumentPropertyPermissionWorkspaceContext extends UmbControllerBase { + constructor(host: UmbControllerHost) { + super(host); + + // Consume the document workspace context + this.consumeContext( + UMB_DOCUMENT_WORKSPACE_CONTEXT, + (context) => { + + // Observe the specific property of the Content Type, to retrieve the unique. + this.observe(context?.structure.propertyStructureByAlias('myNoneWritableProperty'), (property) => { + if(property) { + // Create a guard rule: + const rule = { + unique: 'myCustomRuleIdentifier', + permitted: false, + message: "The property is not writable because of my custom restriction.", + propertyType: { + unique: property.unique + } + } + // Add the rule to the write guard + context.propertyWriteGuard.addRule(rule); + } + }); + } + ); + } +} + +export { MyDocumentPropertyPermissionWorkspaceContext as api }; +``` +{% endcode %} + +The next example will adjust the rule so it only prevents writing on a specific culture. + +### Write a rule for a specific property or a specific variant + +The following example shows how you can make your rule very specific by targeting a property and a `VariantID`. + +**Adjusting the rule for the Workspace Context:** + +{% code title="WorkspaceContext.ts" %} +```typescript +import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; + +... + + // Create a guard rule: + const rule = { + unique: 'myCustomRuleIdentifier', + permitted: false, + message: "The property is not writable because of my custom restriction.", + propertyType: { + unique: property.unique + } + variantId: UmbVariantId.CreateFromPartial({culture: 'en-US'}); + +... +``` +{% endcode %} + +You are in charge of the combination, from targeting everything to targeting a specific property on a specific variant. The last combination purely targets a variant. This means that all properties with values of that variant is also available. diff --git a/17/umbraco-cms/customizing/searchable-trees.md b/17/umbraco-cms/customizing/searchable-trees.md new file mode 100644 index 00000000000..b569a0ef57f --- /dev/null +++ b/17/umbraco-cms/customizing/searchable-trees.md @@ -0,0 +1,165 @@ +# Searchable Trees (ISearchableTree) + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +When you type a search term into the Umbraco backoffice search field, you'll see search results from all the Section Trees that your user account has permission to access: + +![Content Section Dashboards](<../../../10/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png>) + +The results are grouped by 'Section Tree' like Content, Media, Document Types. Each 'Tree' has its own associated search mechanism that receives the search term and looks for matches in the tree that is responsible for searching. + +You can create your own search mechanisms for your own custom sections or replace the default search implementation for a particular section tree. + +## Custom Tree Search + +To create a search for your own custom tree you need to create a C# class that implements the interface `Umbraco.Cms.Core.Trees.ISearchableTree`. + +### ISearchableTree + +```csharp +using System.Collections.Generic; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Models.ContentEditing; + +namespace My.Website; + +public interface ISearchableTree : IDiscoverable +{ + /// + /// The alias of the tree that the belongs to + /// + string TreeAlias { get; } + + /// + /// Searches for results based on the entity type + /// + /// The search term used for finding matching results. + /// The number of records to return for a page of results. + /// The 0-based index for retrieving a page of search results. + /// Populated with the total number of results matching the provided search term. + /// + /// The starting point for the search, generally a node ID, but for members this is a member type alias. + /// + /// + Task SearchAsync(string query, int pageSize, long pageIndex, string? searchFrom = null); +} +``` + +Your implementation needs to return an IEnumerable of `SearchResultEntity` items: + +```csharp +public class SearchResultEntity : EntityBasic +{ + public SearchResultEntity() { + /// + /// The score of the search result + /// + [DataMember(Name = "score")] + public float Score { get; set; } + }; + +} +``` + +A `SearchResultEntity` consists of a Score (a Float value) identifying its relevance to the search term, and the set of `EntityBasic` properties that all Umbraco objects share: eg Name, Id, Udi, Icon, Trashed, Key, ParentId, Path, Alias, AdditionalData. + +#### Example implementation of ISearchableTree + +If we have a custom section Tree with the alias 'favouriteThingsAlias' (see the [custom tree example](extending-overview/extension-types/tree.md)) then we could implement searchability by creating the following C# class in our site: + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models.ContentEditing; +using Umbraco.Cms.Core.Trees; + +namespace Umbraco.Docs.Samples.Web.Trees; + +public class FavouriteThingsSearchableTree : ISearchableTree +{ + public string TreeAlias => "favouriteThingsAlias"; + + public async Task SearchAsync(string query, int pageSize, long pageIndex, string searchFrom = null) + { + // your custom search implementation starts here + Dictionary favouriteThings = new Dictionary(); + favouriteThings.Add(1, "Raindrops on Roses"); + favouriteThings.Add(2, "Whiskers on Kittens"); + favouriteThings.Add(3, "Skys full of Stars"); + favouriteThings.Add(4, "Warm Woolen Mittens"); + favouriteThings.Add(5, "Cream coloured Unicorns"); + favouriteThings.Add(6, "Schnitzel with Noodles"); + + var searchResults = new List(); + + var matchingItems = favouriteThings.Where(f => f.Value.StartsWith(query, true, System.Globalization.CultureInfo.CurrentCulture)); + foreach (var matchingItem in matchingItems) + { + // Making up the Id/Udi for this example! - these would normally be different for each search result. + searchResults.Add(new SearchResultEntity() + { + Id = 12345, + Alias = "favouriteThingItem", + Icon = "icon-favorite", + Key = new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1"), + Name = matchingItem.Value, + ParentId = -1, + Path = "-1,12345", + Score = 1.0F, + Trashed = false, + Udi = Udi.Create("document", new Guid("325746a0-ec1e-44e8-8f7b-6e7c4aab36d1")) + }); + } + // Set number of search results found + var totalFound = matchingItems.Count(); + // Return your results + return new EntitySearchResults(searchResults, totalFound); + } +} +``` + +That's all we need, after an application pool recycle, if we now search in the backoffice we'll see matches from our custom 'Favourite Things' tree: + +![Content Section Dashboards](<../../../10/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png>) + +Umbraco automatically finds any implementation of `ISearchableTree` in your site and automatically configures it to be used for the custom section mentioned in the TreeAlias property. Be careful not to accidentally have two `ISearchableTree` implementations trying to search the 'same' TreeAlias, it's _one_ `ISearchableTree` per TreeAlias. + +## Replacing an existing Section Tree Search + +Perhaps you want to change the logic for searching an existing section of the site, (why? - well you might have a 'company name' property on a MemberType in the Member section, and you want searches for that company name to filter the members who work there, the default implementation will only search on Member Name). + +Or perhaps you want to replace Examine search in the backoffice with an external Search Service, e.g. Azure Search. In a cloud-hosted implementation you don't need to build the Examine indexes on each new server as your cloud hosting scales out. + +### Example + +First create your replacement custom `ISearchableTree` implementation, using the same approach as above, but specifying the TreeAlias of the Tree you aim to replace, e.g. 'Member'. + +```csharp +public string TreeAlias => "member"; +``` + +To avoid your custom implementation clashing with the default `ISearchableTree` for a Tree, you need to remove its `ISearchableTree` implementation from the collection of SearchableTrees using an `IComposer` when Umbraco starts up: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Web.BackOffice.Trees; + +namespace Umbraco.Docs.Samples.Web.Trees; + +public class RemoveCoreMemberSearchableTreeComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + // Remove core MemberTreeController + builder.SearchableTrees().Exclude(); + } +} +``` + +This would then allow your custom implementation of `ISearchableTree` with TreeAlias 'member' to be used when searching the Member Section Tree. diff --git a/17/umbraco-cms/customizing/section-trees.md b/17/umbraco-cms/customizing/section-trees.md new file mode 100644 index 00000000000..344f1035db2 --- /dev/null +++ b/17/umbraco-cms/customizing/section-trees.md @@ -0,0 +1,29 @@ +--- +description: An explanation on sections and trees in Umbraco +--- + +# Sections & Trees + +{% hint style="warning" %} +The Section & Trees articles are a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The Umbraco backoffice consists of sections (sometimes referred to as applications) which contain Trees. + +Each section is identified by its name in the top navigation ribbon of the Umbraco Backoffice. + +For example, when you load the backoffice, you'll see that the 'Content' section contains one tree: the content tree. Meanwhile, the 'Settings' section contains a number of trees such as Stylesheets, Document Types, Media Types, etc... + +You can create your own sections and trees to extend Umbraco. + +## [Sections](extending-overview/extension-types/sections/section.md) + +Describes Umbraco Sections, configuration, and APIs. + +## [Trees](extending-overview/extension-types/tree.md) + +Describes Umbraco Trees, configuration, APIs, and events. + +## [Searchable Trees (ISearchableTree)](searchable-trees.md) + +Explains how to customize the backoffice search of a Section Tree. diff --git a/17/umbraco-cms/customizing/ui-library.md b/17/umbraco-cms/customizing/ui-library.md new file mode 100644 index 00000000000..ecf66b43dd3 --- /dev/null +++ b/17/umbraco-cms/customizing/ui-library.md @@ -0,0 +1,51 @@ +--- +description: Find out more about Umbraco Backoffice UI Library, Backoffice UI API and Storybook. +--- + +# UI Library + +## UI Library and UI API + +With the UI Library, you get a collection of visual building blocks that consists of pieces to build any UI in Umbraco. Each component is a building block updating its display according to the data passed to it. + +{% hint style="info" %} +**Are you looking for the AngularJS documentation?** + +With Umbraco 14 the Umbraco backoffice has been rebuilt using Web Components and TypeScript. This means that AngularJS is no longer being used in Umbraco CMS, hence the removal of the corresponding documentation. +{% endhint %} + +With the UI API, you get a set of collections related to modules export, interfaces, and hierarchy. This includes code examples and much more that you can use to extend the backoffice. + + +
Backoffice UI LibrarySee, test, and get a feel for the familiar backoffice components built using the new UI components.https://apidocs.umbraco.com/v15/ui/Documentations Icons_Umbraco_CMS_Fundamentals_Backoffice (1) (2).png
Backoffice UI APIFind reference documentation about all types and contexts in the Backoffice.https://apidocs.umbraco.com/v15/ui-api/Documentations Icons_Umbraco_CMS_Fundamentals_Code.png
+ +## UI Library Storybook + +The Umbraco UI Library is a set of web components that can be used to build Umbraco User Interfaces. The UI Library separates the user interface from Umbraco’s business logic and creates a unified user experience. This is done with coherent styling and naming, across all the Umbraco platforms and projects including the ones developed by you. + +[Storybook](https://uui.umbraco.com/) is an application that gathers all the components together of the UI Library. It holds the documentation for the components and showcases different use case scenarios. You can explore all the components through stories reflecting their use cases. + +Each story has interactive controls that allow you to change the state of the component in real time. Every publicly available property is editable in Storybook, so you can test out custom configurations and use cases. + +You can also modify the custom properties in the stylesheet to see how the component will look. Every story has a code example that you can copy and paste into your project. This will allow you to implement the components in your own packages and extensions. + +### Getting Started with the UI Library + +The [Storybook](https://uui.umbraco.com/) is the starting point for working with the Umbraco UI Library. The Storybook contains two tabs: + +1. Canvas - The Canvas tab allows to use the interactive controls. + +
+2. Documentation - Here, you can find code examples for all the stories and use them in your markup. You can look it up by tag name or head to the project repository, where, in the packages folder, you will find all the component packages with all the necessary scripts and examples in the readme files. + +
+ +### Import UI Library Components + +You can also work with the components on a code level. If you want to do so here is how you import it: + +```typescript +import { UUIButtonElement } from '@umbraco-cms/backoffice/external/uui'; +``` + +This requires that your Package has the `@umbraco-cms/backoffice` dependency. diff --git a/17/umbraco-cms/customizing/umbraco-package.md b/17/umbraco-cms/customizing/umbraco-package.md new file mode 100644 index 00000000000..c19fe820ed2 --- /dev/null +++ b/17/umbraco-cms/customizing/umbraco-package.md @@ -0,0 +1,173 @@ +--- +description: An extension begins with a Umbraco Package +--- + +# Umbraco Package + +A Package is declared via an Umbraco Package JSON file. This describes the Package and declares one or more UI Extensions. The Package declaration is a JSON file that is stored in the `App_Plugins/{YourPackageName}` folder. The file is named `umbraco-package.json`. + +## Sample + +Here is a sample package. It should be stored in a folder in `App_Plugins/{YourPackageName}`, with the name `umbraco-package.json`. In this example, the package name is `SirTrevor` and is a text box property Data Type. + +{% hint style="info" %} +Before Umbraco 14, a package was declared in a `package.manifest` file instead of `umbraco-package.json`. The old format is no longer supported, but you can migrate the contents to the new format. +{% endhint %} + +{% code title="umbraco-package.json" lineNumbers="true" %} +```json +{ + "id": "My.Nuget.Package", + "name": "Sir Trevor", + "version": "1.0.0-beta", + "extensions": [ + { + "type": "propertyEditorUi", + "alias": "Sir.Trevor", + "name": "Sir Trevor Property Editor UI", + "element": "/App_Plugins/SirTrevor/SirTrevor.js", + "meta": { + "label": "Sir Trevor", + "propertyEditorSchemaAlias": "Umbraco.TextBox", + "icon": "icon-code", + "group": "Pickers" + } + } + ] +} +``` +{% endcode %} + +## Root fields + +The `umbraco-package` accepts these fields: + +```json +{ + "id": "", + "name": "", + "version": "", + "allowTelemetry": true, + "allowPublicAccess": false, + "importmap": { + "imports": { + "": "" + }, + "scopes": { + "": "" + } + }, + "extensions": [] +} +``` + +### Id + +The unique identifier for your package. This is used to identify your package and should be unique to your package. If you are creating a package that is distributed via NuGet, you should use the NuGet package ID as the ID for your package. + +### Name + +Allows you to specify a friendly name for your package that will be used for telemetry. If no name is specified the name of the folder will be used instead. + +### Version + +The version of your package, if this is not specified there will be no version-specific information for your package. This is used for telemetry and to help users understand what version of your package they are using. It is also used for package migrations. The version should follow the [Semantic Versioning](https://semver.org/) format. + +### Allow Telemetry + +With this field, you can control the telemetry of this package, this will provide Umbraco with the knowledge of how many installations use this package. + +The default is `true`. + +Also known as: `allowPackageTelemetry` + +### Allow Public Access + +This field is used to allow public access to the package. If set to `true`, the package will be available for anonymous usage, for example on the login screen. If set to `false`, the package will only be available to logged-in users. + +The default is `false`. + +### Importmap + +The `importmap` field is an object that contains two properties: `imports` and `scopes`. This is used to define the import map for the package. The `imports` property is an object that contains the import map for the package. The `scopes` property is an object that contains the scopes for the package. + +**Example** + +This example shows how to define an import map for a module exported by a package: + +{% code title="umbraco-package.json" lineNumbers="true" %} +```json +{ + "importmap": { + "imports": { + "mypackage/services": "/App_Plugins/MyPackage/services/index.js", + } + } +} +``` +{% endcode %} + +The `imports` object contains the import map for the package. The key is the specifier for the module that is being imported, and the value is the URL of the module. + +This allows developers to consume modules that are exported by a package without having to know the exact path to the module: + +{% code title="index.js" %} +```javascript +import { MyService } from 'mypackage/services'; +``` +{% endcode %} + +Umbraco supports the current specification of the property as outlined on MDN Web Documentation: [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap). + +### Extensions + +The `extensions` field is an array of Extension Manifest objects. Each object describes a single client extension. + +Read more about Extension Types in the Backoffice to get a better understanding of the different types of extensions: + +{% content-ref url="extending-overview/extension-types/README.md#full-list-of-extension-types" %} +[extending-overview/extension-types/README.md#full-list-of-extension-types](extending-overview/extension-types/README.md#full-list-of-extension-types) +{% endcontent-ref %} + +## Package Manifest IntelliSense + +Make your IDE be aware about the opportunities of the `umbraco-package.json` by adding a JSON schema. This gives your code editor abilities to autocomplete and knowledge about the format. This helps to avoid mistakes or errors when editing the `umbraco-package.json` file. + +### Adding inline schema + +Editors like Visual Studio can use the `$schema` notation in your file. + +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "" +} +``` + +Hover over any of the properties to see the description of the property. You can also use the `Ctrl + Space` (Windows/Linux) or `CMD + Space` (macOS) shortcut to see the available properties. + +## Load Package Manifest files + +Umbraco scans the `App_Plugins` folder for `umbraco-package.json` files **two levels deep**. When found, the packages are loaded into the system. + +You may need to restart the application, if you add a new file or modify an existing manifest: + +If the runtime mode is `Production`, the manifests are cached for 30 days or until the application is restarted to improve performance. In other runtime modes, the cache is cleared every 10 seconds. + +{% hint style="info" %} +You can implement the interface [IPackageManifestReader](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Infrastructure.Manifest.IPackageManifestReader.html) to provide your own package manifest reader. This can be useful if you want to load package manifests from a different location or source. +{% endhint %} + +## Razor Class Library + +Umbraco also supports [Razor Class Library (RCL)](https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-8.0\&tabs=visual-studio#create-an-rcl-with-static-assets) projects that contain static web assets. The `umbraco-package.json` file can be placed in the `wwwroot` folder of the RCL project. The package will be loaded when the RCL is referenced by the main project. You must map the web path to `App_Plugins` in your `.csproj` file: + +{% code title="MyProject.Assets.csproj" %} +```xml + + App_Plugins/{YourPackageName} + +``` +{% endcode %} + +Read more about getting set up for Backoffice development in the [Customize Backoffice](overview.md) section. diff --git a/17/umbraco-cms/customizing/workspaces.md b/17/umbraco-cms/customizing/workspaces.md new file mode 100644 index 00000000000..9606400ec88 --- /dev/null +++ b/17/umbraco-cms/customizing/workspaces.md @@ -0,0 +1,24 @@ +# Workspaces + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A Workspace is the editor for a specific entity type. It can either be a view of data or a complex editor with multiple views. + +* A workspace is based on an entity type (for example content, media, member, etc.) and a unique string (ex: key). +* Most workspaces hold a draft state of an entity. It is a copy of the entity data that can be modified at runtime and sent to the server to be saved. +* A workspace can be a single view or consist of multiple views. +* A workspace should host a workspace context, with which anything within can communicate. + +

Workspace

+ +```ts +interface UmbWorkspaceElement {} +``` + +## [Workspace Context](extending-overview/extension-types/workspaces/workspace-context.md) + +## [Workspace Views](extending-overview/extension-types/workspaces/workspace-views.md) + +## [Workspace Actions](extending-overview/extension-types/workspaces/workspace-editor-actions.md) diff --git a/17/umbraco-cms/examples-and-playground.md b/17/umbraco-cms/examples-and-playground.md new file mode 100644 index 00000000000..1858631fc82 --- /dev/null +++ b/17/umbraco-cms/examples-and-playground.md @@ -0,0 +1,31 @@ +--- +description: Practical examples and hands-on experience are good ways to learn. +--- + +# Examples and Playground + +The Umbraco CMS codebase comes with a set of customization examples and a way to run them using a local front-end server. This setup enables you to change the code and review the effects instantly by refreshing your browser. + +[Browse the available examples in the Umbraco CMS Repository](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Web.UI.Client/examples). + +## Get Started + +1. Clone the source code from [https://github.com/umbraco/Umbraco-CMS/](https://github.com/umbraco/Umbraco-CMS/). +2. Make sure you have **npm** installed. +3. Open a terminal and navigate to `src/Umbraco.Web.UI.Client` . +4. Run the command: `npm install` . + +### Run an Example + +Start a local server and run one of the examples: `npm run example` . + +### Create a playground + +You can add a new example and use it as your playground. If it covers a specific topic that would be of interest to others, you can contribute it as a pull request. + +To create a new example, follow these steps: + +1. Create a new folder with a name of your choice in the `examples/` folder. +2. Add an `index.ts` file that exports an array of manifests as the default export (See the other examples if in doubt). +3. Run your example using the command listed above in [Run an example](examples-and-playground.md#run-an-example). + diff --git a/17/umbraco-cms/extending/backoffice-search.md b/17/umbraco-cms/extending/backoffice-search.md new file mode 100644 index 00000000000..885e47d8cde --- /dev/null +++ b/17/umbraco-cms/extending/backoffice-search.md @@ -0,0 +1,103 @@ +--- +description: A guide to customization of Backoffice Search +--- + +# Backoffice Search + +The search facility of the Umbraco Backoffice allows the searching 'across sections' of different types of Umbraco entities, for example Content, Media, Members. However 'by default' only a small subset of standard fields are searched: + +| Node Type | Propagated Fields | +| ------------ | ---------------------- | +| All Nodes | Id, _NodeId_ and _Key_ | +| Media Nodes | UmbracoFileFieldName | +| Member Nodes | email, loginName | + +An Umbraco implementation might have additional custom properties that it would be useful to include in a Backoffice Search. For example: an 'Organisation Name' property on a Member Type, or a 'Product Code' field for a 'Product' content item. + +## Adding custom properties to backoffice search + +To add custom properties, it is required to register a custom implementation of `IUmbracoTreeSearcherFields`. We recommend to override the existing `UmbracoTreeSearcherFields`. + +Your custom implementation needs to be registered in the container. For example in the `Program.cs` file or in a composer, as an alternative. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .Build(); + +builder.Services.AddUnique(); +``` + +or + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Infrastructure.Examine; +using Umbraco.Extensions; + +namespace Umbraco.Docs.Samples.Web.BackofficeSearch; + +public class BackofficeSearchComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + } +} +``` + +{% hint style="warning" %} +The below example is using `ILocalizationService` which is currently obsolete and will be removed in v15. Use `ILanguageService` instead. +{% endhint %} + +```csharp +using System.Collections.Generic; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Examine; +using Umbraco.Cms.Infrastructure.Search; + +namespace Umbraco.Docs.Samples.Web.BackofficeSearch; + +public class CustomUmbracoTreeSearcherFields : UmbracoTreeSearcherFields, IUmbracoTreeSearcherFields +{ + public CustomUmbracoTreeSearcherFields(ILocalizationService localizationService) : base(localizationService) + { + } + + //Adding custom field to search in all nodes + public new IEnumerable GetBackOfficeFields() + { + return new List(base.GetBackOfficeFields()) { "nodeType" }; + } + + //Adding custom field to search in document types + public new IEnumerable GetBackOfficeDocumentFields() + { + return new List(base.GetBackOfficeDocumentFields()) { "nodeType" }; + } + + //Adding custom field to search in media + public new IEnumerable GetBackOfficeMediaFields() + { + return new List(base.GetBackOfficeMediaFields()) { "nodeType" }; + } + + //Adding custom field to search in members + public new IEnumerable GetBackOfficeMembersFields() + { + return new List(base.GetBackOfficeMembersFields()) { "nodeType" }; + } +} +``` + +{% hint style="warning" %} +You cannot use this to search on integer types in the index, as an example `parentID` does not work. +{% endhint %} + +## More advanced extensions + +For further extensibility of the Umbraco Backoffice search implementation check [ISearchableTree](../customizing/searchable-trees.md) diff --git a/17/umbraco-cms/extending/build-on-umbraco-functionality.md b/17/umbraco-cms/extending/build-on-umbraco-functionality.md new file mode 100644 index 00000000000..a32a1bc6c98 --- /dev/null +++ b/17/umbraco-cms/extending/build-on-umbraco-functionality.md @@ -0,0 +1,38 @@ +--- +description: >- + Learn more about how to extend and build in the features and functionalities + with the Umbraco CMS. +--- + +# Build on Umbraco functionality + +One of the biggest strengths of the Umbraco CMS is its flexibility. It is possible to extend and customize all aspects of the product, tailoring it to fit perfectly to any project. + +{% hint style="info" %} +Are you looking to **customize and build extensions for the Umbraco backoffice?** + +All articles related to customizing and extending the Umbraco backoffice have been moved to the [Customize the Backoffice](../customizing/overview.md) section. +{% endhint %} + +In this section, you can find resources to build and extend Umbraco CMS functionality. + +
Backoffice SearchLearn how to customize the built-in search functionality in the backoffice.Documentations Icons_Umbraco_CMS_Reference_Searching.pngbackoffice-search.md
PackagesAdd your custom code into packages and distribute them to the rest of the Umbraco users.Documentations Icons_Umbraco_CMS_Extending_Packages.pngpackages
Health ChecksLearn about the health checks that you can run on your site to verify its state.Documentations Icons_Umbraco_CMS_Extending_Health_Checks.pnghealth-check
+ +## Other ways to extend the Umbraco CMS backoffice + +* [Embedded Media Providers](embedded-media-providers.md) +* [Language files and localization](language-files/) + +## Also in this section + +{% content-ref url="database.md" %} +[database.md](database.md) +{% endcontent-ref %} + +{% content-ref url="key-vault.md" %} +[key-vault.md](key-vault.md) +{% endcontent-ref %} + +{% content-ref url="filesystemproviders/" %} +[filesystemproviders](filesystemproviders/) +{% endcontent-ref %} diff --git a/17/umbraco-cms/extending/creating-custom-seed-key-provider.md b/17/umbraco-cms/extending/creating-custom-seed-key-provider.md new file mode 100644 index 00000000000..3ce53918471 --- /dev/null +++ b/17/umbraco-cms/extending/creating-custom-seed-key-provider.md @@ -0,0 +1,116 @@ +--- +description: A guide to creating a custom seed key provider for Umbraco +--- + +# Creating a Custom Seed Key Provider + +Umbraco uses a lazy loaded cache, which means that content is loaded into the cache on an as-needed basis. However, you may need specific content to always be in the cache. To achieve this you can implement your own custom seed key providers. + +There are two types of seed key providers: `IDocumentSeedKeyProvider` for documents and `IMediaSeedKeyProvider` for media. As these interfaces are identical only `IDocumentSeedKeyProvider` is demonstrated in this article. + +{% hint style="warning" %} +Seed keys are cached and calculated once. Any documents created after the site has started will not be included in the seed keys until after a server restart. +{% endhint %} + +## Implementation + +This example implements a `IDocumentSeedKeyProvider` which seeds all the children of a node, in this case blog posts. + +1. Create a new class called `BlogSeedKeyProvider` that implements `IDocumentSeedKeyProvider`. + +```csharp +using Umbraco.Cms.Infrastructure.HybridCache; + +namespace MySite.SeedKeyProviders; + +public class BlogSeedKeyProvider : IDocumentSeedKeyProvider +{ + public ISet GetSeedKeys() + { + } +} +``` + +2. Inject the `IDocumentNavigationQueryService` to get the children of the blog node. + +```csharp +using Umbraco.Cms.Core.Services.Navigation; +using Umbraco.Cms.Infrastructure.HybridCache; + +namespace MySite.SeedKeyProviders; + +public class BlogSeedKeyProvider : IDocumentSeedKeyProvider +{ + private readonly IDocumentNavigationQueryService _documentNavigationQueryService; + + public BlogSeedKeyProvider(IDocumentNavigationQueryService documentNavigationQueryService) + => _documentNavigationQueryService = documentNavigationQueryService; + +{...} +``` + +3. Parse a hardcoded string to a GUID. +4. Use the `IDocumentNavigationQueryService` to get the children of the blog node. +5. Return their keys as a `HashSet`. + +```csharp +public ISet GetSeedKeys() +{ + var blogRoot = Guid.Parse("a5fdb22d-b7f2-4a59-8c4e-46ed86bde56c"); + + if (_documentNavigationQueryService.TryGetChildrenKeys(blogRoot, out IEnumerable blogPostKeys)) + { + return new HashSet(blogPostKeys); + } + + return new HashSet(); +} +``` + +Since this returns it as a set, and all the sets get unioned, we do not have to worry about duplicates. + +The final class looks like this: + +```csharp +using Umbraco.Cms.Core.Services.Navigation; +using Umbraco.Cms.Infrastructure.HybridCache; + +namespace MySite.SeedKeyProviders; + +public class BlogSeedKeyProvider : IDocumentSeedKeyProvider +{ + private readonly IDocumentNavigationQueryService _documentNavigationQueryService; + + public BlogSeedKeyProvider(IDocumentNavigationQueryService documentNavigationQueryService) + => _documentNavigationQueryService = documentNavigationQueryService; + + public ISet GetSeedKeys() + { + var blogRoot = Guid.Parse("a5fdb22d-b7f2-4a59-8c4e-46ed86bde56c"); + + if (_documentNavigationQueryService.TryGetChildrenKeys(blogRoot, out IEnumerable blogPostKeys)) + { + return new HashSet(blogPostKeys); + } + + return new HashSet(); + } +} +``` + +### Registering the Seed Key Provider + +Now that the `BlogSeedKeyProvider` is implemented, it must be registered in the `Startup` class. + +```csharp +using MySite.SeedKeyProviders; +using Umbraco.Cms.Infrastructure.DependencyInjection; +using Umbraco.Cms.Infrastructure.HybridCache; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +builder.Services.AddSingleton(); +{...} +``` + +All blogpost will now be seeded into the cache on startup, and will always be present in the cache. diff --git a/17/umbraco-cms/extending/customize-backoffice/development-flow/images/vite-project-cli.jpg b/17/umbraco-cms/extending/customize-backoffice/development-flow/images/vite-project-cli.jpg new file mode 100644 index 00000000000..2258c172c82 Binary files /dev/null and b/17/umbraco-cms/extending/customize-backoffice/development-flow/images/vite-project-cli.jpg differ diff --git a/17/umbraco-cms/extending/database.md b/17/umbraco-cms/extending/database.md new file mode 100644 index 00000000000..423150c9bd5 --- /dev/null +++ b/17/umbraco-cms/extending/database.md @@ -0,0 +1,288 @@ +--- +description: A guide to creating a custom Database table in Umbraco +--- + +# Creating a Custom Database Table + +Umbraco ships with [NPoco](https://github.com/schotime/NPoco), which enables mapping the results of database queries to Common Language Runtime (CLR) objects. NPoco allows custom database tables to be added to your site to store additional data that should not be stored as normal content nodes. + +The end result looks like this: + +![Database result of a migration](<../../../10/umbraco-cms/extending/images/db-table (1) (1) (1).png>) + +## Using a Composer and Component + +The following code sample shows how this is done using a composer and component. + +When migrating from version 8 there are a few changes to be aware of. The first change is that namespace updates are dependencies that need to be passed to the `Upgrader.Execute()` method. Another is a change to the access modifier of the `Migrate()` method. + +```csharp +using Microsoft.Extensions.Logging; +using NPoco; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Migrations; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade; +using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; + +namespace MyNamespace; + +public class BlogCommentsComposer : ComponentComposer +{ +} + +public class BlogCommentsComponent : IComponent +{ + private readonly ICoreScopeProvider _coreScopeProvider; + private readonly IMigrationPlanExecutor _migrationPlanExecutor; + private readonly IKeyValueService _keyValueService; + private readonly IRuntimeState _runtimeState; + + public BlogCommentsComponent( + ICoreScopeProvider coreScopeProvider, + IMigrationPlanExecutor migrationPlanExecutor, + IKeyValueService keyValueService, + IRuntimeState runtimeState) + { + _coreScopeProvider = coreScopeProvider; + _migrationPlanExecutor = migrationPlanExecutor; + _keyValueService = keyValueService; + _runtimeState = runtimeState; + } + + public void Initialize() + { + if (_runtimeState.Level < RuntimeLevel.Run) + { + return; + } + + // Create a migration plan for a specific project/feature + // We can then track that latest migration state/step for this project/feature + var migrationPlan = new MigrationPlan("BlogComments"); + + // This is the steps we need to take + // Each step in the migration adds a unique value + migrationPlan.From(string.Empty) + .To("blogcomments-db"); + + // Go and upgrade our site (Will check if it needs to do the work or not) + // Based on the current/latest step + var upgrader = new Upgrader(migrationPlan); + upgrader.Execute(_migrationPlanExecutor, _coreScopeProvider, _keyValueService); + } + + public void Terminate() + { + } +} + +public class AddCommentsTable : MigrationBase +{ + public AddCommentsTable(IMigrationContext context) : base(context) + { + } + protected override void Migrate() + { + Logger.LogDebug("Running migration {MigrationStep}", "AddCommentsTable"); + + // Lots of methods available in the MigrationBase class - discover with this. + if (TableExists("BlogComments") == false) + { + Create.Table().Do(); + } + else + { + Logger.LogDebug("The database table {DbTable} already exists, skipping", "BlogComments"); + } + } + + [TableName("BlogComments")] + [PrimaryKey("Id", AutoIncrement = true)] + [ExplicitColumns] + public class BlogCommentSchema + { + [PrimaryKeyColumn(AutoIncrement = true, IdentitySeed = 1)] + [Column("Id")] + public int Id { get; set; } + + [Column("BlogPostUmbracoId")] + public int BlogPostUmbracoId { get; set; } + + [Column("Name")] + public required string Name { get; set; } + + [Column("Email")] + public required string Email { get; set; } + + [Column("Website")] + public required string Website { get; set; } + + [Column("Message")] + [SpecialDbType(SpecialDbTypes.NVARCHARMAX)] + public string Message { get; set; } + } +} +``` + +## Using a Notification Handler + +If building a new solution, you can adopt a new pattern. With this pattern you create and run a similar migration but trigger it in response to a [notification handler](../fundamentals/code/subscribing-to-notifications.md). + +The code for this approach is as follows: + +```csharp +using Microsoft.Extensions.Logging; +using NPoco; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Migrations; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade; +using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; + +namespace MyNamespace; + +public class RunBlogCommentsMigration : INotificationHandler +{ + private readonly IMigrationPlanExecutor _migrationPlanExecutor; + private readonly ICoreScopeProvider _coreScopeProvider; + private readonly IKeyValueService _keyValueService; + private readonly IRuntimeState _runtimeState; + + public RunBlogCommentsMigration( + ICoreScopeProvider coreScopeProvider, + IMigrationPlanExecutor migrationPlanExecutor, + IKeyValueService keyValueService, + IRuntimeState runtimeState) + { + _migrationPlanExecutor = migrationPlanExecutor; + _coreScopeProvider = coreScopeProvider; + _keyValueService = keyValueService; + _runtimeState = runtimeState; + } + + public void Handle(UmbracoApplicationStartingNotification notification) + { + if (_runtimeState.Level < RuntimeLevel.Run) + { + return; + } + + // Create a migration plan for a specific project/feature + // We can then track that latest migration state/step for this project/feature + var migrationPlan = new MigrationPlan("BlogComments"); + + // This is the steps we need to take + // Each step in the migration adds a unique value + migrationPlan.From(string.Empty) + .To("blogcomments-db"); + + // Go and upgrade our site (Will check if it needs to do the work or not) + // Based on the current/latest step + var upgrader = new Upgrader(migrationPlan); + upgrader.Execute( + _migrationPlanExecutor, + _coreScopeProvider, + _keyValueService); + } +} + +// Migration and schema defined as in the previous code sample. +``` + +The notification handler can be registered in a composer: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Notifications; + +namespace TableMigrationTest; + +public class BlogCommentsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + } +} +``` + +## Which to use? + +In short, it's up to you. If you are migrating from version 8 and want the quickest route to getting running with the latest version, then using a component makes sense. + +You will be using the notification pattern elsewhere. This could be when responding to Umbraco events that run many times in the lifetime of the application, like when content is saved. And so you may also prefer to align with that pattern for start-up events. + +It is also worth noting that components offer both `Initialize` and `Terminate` methods. With these you will need to handle two notifications to do the same with the notification handler approach (`UmbracoApplicationStartingNotification` and `UmbracoApplicationStoppingNotification`). A single handler class can be used for both notifications though. + +## Schema Class and Migrations + +**Important!** The `BlogCommentSchema` class nested inside the migration is purely used as a database schema representation class. It should not be used as a Data Transfer Object (DTO) to access the table data. Equally, you shouldn't use your DTO classes to define the schema used by your migration. Instead, you should create a duplicate snapshot for the purpose of creating or working with your database tables in the current migration. The name of the class is not important as you will be overriding it using the TableName attribute. You should choose a name that makes it clear that this class is purely for defining the schema in this migration. + +Whilst this adds a level of duplication, it is important that migrations and the code/classes within a migration remain immutable. If the DTO was to be used for both, it could cause unexpected behaviour. Should you later modify your DTO used in your application but you have previous migrations expecting the DTO to be in its unmodified state. + +Once a snapshot has been created, and once your code has been deployed, the snapshot should never be changed directly. Instead, you should use further migrations to alter the database table into the state you require. This ensures that migrations can be run in sequence and that each migration can expect the database to be in a known state before executing. + +When adding further migrations and if you need to reuse the schema class, it is a good idea to duplicate this in those particular migrations. You want the migrations to be immutable. Having separate classes in separate namespaces, reduces the risk of modifying a schema class from your initial migration. + +## Data stored in Custom Database Tables + +When storing data in custom database tables, this is by default not manageable by Umbraco at all. This can be great for many purposes such as storing massive amounts of data that you do not need to edit from the backoffice. Decoupling part of your data from being managed by Umbraco as content can be a way of achieving better performance for your site. It will no longer take up space in indexes and caches, and the Umbraco database. + +This also means that if you do need to edit or display this data, you need to implement the underlying functionality to support this. The same if the case if you need this data to be transferred or kept synchronized between multiple sites or environments. Data stored in custom tables are not supported by default by add-ons such as Umbraco Deploy and will not be deployable by default. + +Figuring out how to manage data across multiple environments can be different between individual sites and there is not one solution that fits all. Some sites may have automated database synchronization set up to ensure specific tables in multiple databases are always kept in sync. Other sites may be better off with scripts moving data around manually on demand. + +## Working with data in Custom Database Tables + +To create, read, update or delete data from your custom database tables, you can use the `IScopeProvider` to get access to the database operations. + +The following example creates a `Controller` that uses `[Route]` annotations to create API endpoints for fetching and inserting blog comments. + +{% hint style="info" %} +This example does not use the aforementioned `BlogCommentSchema` class but rather a separate (yet duplicate) class that is not part of the example. Also, be aware that things like error handling and data validation have been omitted for brevity. +{% endhint %} + +```csharp +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using Umbraco.Cms.Infrastructure.Scoping; + +namespace MyNamespace; + +[ApiController] +[Route("/umbraco/api/blogcomments")] +public class BlogCommentsApiController : Controller +{ + private readonly IScopeProvider _scopeProvider; + public BlogCommentsApiController(IScopeProvider scopeProvider) + { + _scopeProvider = scopeProvider; + } + + [HttpGet("getcomments")] + public IEnumerable GetComments(int umbracoNodeId) + { + using var scope = _scopeProvider.CreateScope(); + var queryResults = scope.Database.Fetch("SELECT * FROM BlogComments WHERE BlogPostUmbracoId = @0", umbracoNodeId); + scope.Complete(); + return queryResults; + } + + [HttpPost("insertcomment")] + public void InsertComment(BlogComment comment) + { + using var scope = _scopeProvider.CreateScope(); + scope.Database.Insert(comment); + scope.Complete(); + } +} +``` diff --git a/17/umbraco-cms/extending/embedded-media-providers.md b/17/umbraco-cms/extending/embedded-media-providers.md new file mode 100644 index 00000000000..01978f63075 --- /dev/null +++ b/17/umbraco-cms/extending/embedded-media-providers.md @@ -0,0 +1,187 @@ +--- +description: A guide to creating a custom embed providers in Umbraco +--- + +# Embedded Media Providers + +The Rich Text Editor in Umbraco has an 'Embed' button, that when pressed, slides open a panel. This panel enables editors to paste the URL of a third-party media resource to embed in content. + +![The Rich Text Editor Embed Button](images/Embed-Button.png) + +For example, a YouTube Video: + +![Embedding a music video from YouTube](images/Embed-YouTube.png) + +The task of an `EmbedProvider` is to accept the pasted URL and write out the appropriate markup for the third-party provider associated with the URL. + +## Embed Provider Configuration + +Embed Providers are registered with the `EmbedProvidersCollection` during Composition when Umbraco boots. + +The list of available default Embed Providers in an Umbraco install is as follows: + +* YouTube +* YouTube Shorts +* Twitter (removed with version 14.2) +* X (available from version 14.2) +* Vimeo +* Dailymotion +* Flickr +* SlideShare +* Kickstarter +* Getty Images +* Ted +* SoundCloud +* Issuu +* Hulu +* Giphy + +You can see the details of these, and any recent editions in the C# developer reference for [Umbraco.Core.Media.EmbedProviders](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Media.EmbedProviders.html). + +## Configuring a new provider + +Create a new provider by creating a C# class that implements the `IEmbedProvider` interface. Umbraco provides a convenient `OEmbedProviderBase` class as a starting point. You can read more about this class in the [Api documentation](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Media.EmbedProviders.OEmbedProviderBase.html?q=OEmbedProviderBase). + +### Adding a new OEmbed Provider Example + +Let's allow our editors to embed artwork from the popular DeviantArt website - the world's largest online social community for artists and art enthusiasts. We can see they have information on using OEmbed: [https://www.deviantart.com/developers/oembed](https://www.deviantart.com/developers/oembed). The format of their OEmbed implementation returns a JSON format, from a URL `https://backend.deviantart.com/oembed?url=[urltoembed]`. We'll need to use the `OEmbedProviderBase` and the `base.GetJsonResponse` method. We can see 'links' to media shared on DeviantArt are in the format: `https://fav.me/[uniquemediaidentifier]`. We'll need a regex to match any URLs pasted into the embed panel that start with _fav.me_, achieved by setting the `UrlSchemeRegex` property. + +The Provider would look like this: + +{% code title="DeviantArtEmbedProvider.cs" lineNumbers="true" %} +```csharp +using Umbraco.Cms.Core.Media.EmbedProviders; +using Umbraco.Cms.Core.Serialization; + +namespace MyNamespace; + +public class DeviantArtEmbedProvider : OEmbedProviderBase +{ + public DeviantArtEmbedProvider(IJsonSerializer jsonSerializer) + : base(jsonSerializer) + { + } + + public override string ApiEndpoint => "https://backend.deviantart.com/oembed?url="; + + public override string[] UrlSchemeRegex => new[] + { + @"fav\.me/*", + @"\w+\.deviantart.com\/\w+\/art\/*", + @"\w+\.deviantart.com\/art\/*", + @"sta\.sh/*", + @"\w+\.deviantart.com\/\w+#\/d*" + }; + + public override Dictionary RequestParams => new(); + + public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + return GeOEmbedDataAsync(url, maxWidth, maxHeight, CancellationToken.None).GetAwaiter().GetResult(); + } + + public override async Task GeOEmbedDataAsync(string url, int? maxWidth, int? maxHeight, CancellationToken cancellationToken) + { + var requestUrl = base.GetEmbedProviderUrl(url, maxWidth, maxHeight); + OEmbedResponseWithStringDimensions? oembed = await base.GetJsonResponseAsync(requestUrl, cancellationToken); + + return oembed?.GetHtml(); + } +} +``` +{% endcode %} + +#### Register the provider with the `EmbedProvidersCollection` + +Create a new C# class that implements `IComposer` and append your new provider to the `EmbedProvidersCollection`: + +{% code title="RegisterEmbedProvidersComposer.cs" lineNumbers="true" %} +```csharp +using Umbraco.Cms.Core.Composing; + +namespace MyNamespace; + +public class RegisterEmbedProvidersComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.EmbedProviders().Append(); +} +``` +{% endcode %} + +The new provider should be available for editors to use: + +![Embedding a Media Item from DeviantArt website](images/deviantart-embedded-media.png) + +Notice there isn't any implementation written here. The regex maps the incoming URL to the provider. The base methods handle the complication of requesting from the third-party API and turning the response into HTML. + +## Custom Embed Providers + +If your third-party media provider lacks OEmbed support or requires custom HTML due to content quirks, implement `GetMarkup()` without using base helper methods. + +### Custom Embed Provider Example + +Azure Media Services [(https://azure.microsoft.com/en-gb/services/media-services/)](https://azure.microsoft.com/en-gb/services/media-services/) provides 'broadcast-quality' video streaming services. You can embed the Azure Media Player into your site to play a video using an IFrame. + +You can create a custom `EmbedProvider` to embed an IFrame video player in your content. This can be done by taking the Media asset URL and writing out the required markup. + +{% code title="AzureVideoEmbedProvider.cs" lineNumbers="true" %} +```csharp +using System.Net; +using Umbraco.Cms.Core.Media.EmbedProviders; +using Umbraco.Cms.Core.Serialization; + +namespace MyNamespace; + +public class AzureVideoEmbedProvider : OEmbedProviderBase +{ + public AzureVideoEmbedProvider(IJsonSerializer jsonSerializer) + : base(jsonSerializer) + { + } + + // no ApiEndpoint! + public override string ApiEndpoint => string.Empty; + + public override string[] UrlSchemeRegex => new[] + { + @"windows\.net/*" + }; + + public override Dictionary RequestParams => new(); + + public override string? GetMarkup(string url, int maxWidth = 0, int maxHeight = 0) + { + // format of markup + string videoFormat = "
"; + + // pass in encoded Url, with and height, and turn off autoplay... + var videoPlayerMarkup = string.Format(videoFormat, WebUtility.UrlEncode(url) + "&autoplay=false", maxWidth, maxHeight); + + return videoPlayerMarkup; + } +} +``` +{% endcode %} + +Here the markup to embed has been manually constructed based upon the iframe video player, no request to an Api endpoint is made... + +#### Register the Azure Embed Provider with the `EmbedProvidersCollection` + +Create a new C# class that implements `IComposer` and add append your new provider to the `EmbedProvidersCollection`: + +{% code title="RegisterEmbedProvidersComposer.cs" lineNumbers="true" %} +```csharp +using Umbraco.Cms.Core.Composing; + +namespace MyNamespace; + +public class RegisterEmbedProvidersComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.EmbedProviders().Append(); +} +``` +{% endcode %} + +Now editors can embed Azure Media video Urls in the format: `//amssamples.streaming.mediaservices.windows.net/3b970ae0-39d5-44bd-b3a3-3136143d6435/AzureMediaServicesPromo.ism/manifest`. diff --git a/17/umbraco-cms/extending/filesystemproviders/README.md b/17/umbraco-cms/extending/filesystemproviders/README.md new file mode 100644 index 00000000000..de857d05cef --- /dev/null +++ b/17/umbraco-cms/extending/filesystemproviders/README.md @@ -0,0 +1,226 @@ +--- +description: A guide to creating custom file systems in Umbraco +--- + +# Custom File Systems (IFileSystem) + +## Media Filesystem + +{% hint style="info" %} +Before considering a custom media file system, be sure to first read about the configuration options for `UmbracoMediaPath` and `UmbracoMediaPhysicalRootPath` in the [configuration reference docs](../../reference/configuration/globalsettings.md). These configurations may save you from creating your own media file system entirely. +{% endhint %} + +By default, Umbraco uses an instance of `PhysicalFileSystem` to handle the storage location of the media archive (wwwroot/media). + +This can be configured by composition: + +```csharp +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Infrastructure.DependencyInjection; + +namespace UmbracoExamples.Composition; + +public class SetMediaFileSystemComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.SetMediaFileSystem((factory) => + { + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + var folderLocation = "~/CustomMediaFolder"; + var rootPath = hostingEnvironment.MapPathWebRoot(folderLocation); + var rootUrl = hostingEnvironment.ToAbsolute(folderLocation); + + return new PhysicalFileSystem( + factory.GetRequiredService(), + hostingEnvironment, + factory.GetRequiredService>(), + rootPath, + rootUrl); + }); + } +} +``` + +When creating a `PhysicalFileSystem` it takes some dependencies like `IIOHelper`, but the last two parameters are what we're interested in. + +The `rootPath` is where your media will be stored on the disk. Since netcore by default stores files in the `wwwroot`, we must put our desired folder somewhere within `wwwroot` to ensure that we use `hostingEnvironment.MapPathWebRoot(~/CustomMediaFolder)`. The `~` will be mapped to your `wwwroot` folder, so the final `rootPath` will be `your/project/path/wwwroot/CustomMediaFolder`. The `~` is therefore important. + +The `rootUrl` is the base URL that your media files will be served from. In this case, your image URL could look something like `mysite.com/CustomMediaFolder/MyAwesomePicture.png`. Again the `~` is important. + +In the code sample above, the `rootUrl` must map to the the same physical location as `rootPath`, which again must be placed under `wwwroot`. If you want to store the media files outside of `wwwroot` there is an extra step involved; you need to instruct netcore to include static files from a different physical location. + +The `rootUrl` is the base URL that your media files will be served from. In this case, your image URL could look something like `mysite.com/CustomMediaFolder/MyAwesomePicture.png`. Again the `~` is important. With the code sample above, the `rootUrl` must map to the same physical location as `rootPath`, otherwise, you will get 404's for your images. + +If you want to store the media files outside of `wwwroot` there is an extra step involved; you need to instruct netcore to include static files from a different physical location. + +In the `Program.cs` file, register a new static file location like so: + +```csharp +... +WebApplication app = builder.Build(); + +app.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider(Path.Combine("C:", "storage", "umbracoMedia")), + RequestPath = "/CustomPath" + }); +``` + +The PhysicalFileProvider takes a single parameter, the **`RootPath`**. This is the rooted filesystem path using directory separator chars and not ending with a directory separator, eg: `c:\storage\umbracoMedia` or `\\server\path`. The safest way to achieve this is using `Path.Combine`. + +You also have to specify the **`RequestPath`**. This is the relative URL where the media will be served using URL separator chars and not ending with a separator, eg: `/CustomPath` or `/Media`. + +Now you can use your newly registered static file location as if it was `wwwroot`. Notice how you no longer need to use `hostingEnvironment.MapPathWebRoot(folderLocation)`, since you're no longer trying to map the location to somewhere within `wwwroot`, but instead use your newly registered static file location. + +```csharp +public void Compose(IUmbracoBuilder builder) +{ + builder.SetMediaFileSystem((factory) => + { + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + var rootPath = Path.Combine("C:", "storage", "umbracoMedia"); + var rootUrl = hostingEnvironment.ToAbsolute("/CustomPath"); + + return new PhysicalFileSystem( + factory.GetRequiredService(), + hostingEnvironment, + factory.GetRequiredService>(), + rootPath, + rootUrl); + }); +} +``` + +This is almost the same as when registering a location within the `wwwroot` folder. The only difference is that `rootPath` is now set to the path we gave the `PhysicalFileProvider` and the `rootUrl` is the same as we set as the `RequestPath` in the `StaticFileOption`. + +Our media is now stored in `C:\storage\umbracoMedia`, and is served from the base URL `/CustomPath`, so an image URL will look something like `mysite.com/CustomPath/MyAwesomePicture.png`. + +### Creating a custom file system + +You can replace `PhysicalFileSystem` with a custom file system implementation - eg. if you want your media files stored on Amazon S3 or elsewhere outside your site. + +To achieve this, you must first create your own file system by implementing the interfaces `IFileSystem` and `IFileProviderFactory` (the interfaces that are implemented by `PhysicalFileSystem`). + +You then replace the media filesystem by composition using `IUmbracoBuilder.SetMediaFileSystem(...)` (as is demonstrated in the paragraphs above), but instead of returning a `PhysicalFileSystem`, you return your own file system implementation. + +For inspiration on building a custom file system, have a look at the [Azure Blob Storage file system implementation](https://github.com/umbraco/Umbraco.StorageProviders#umbracostorageprovidersazureblob). + +### Accessing the media file system from code + +{% hint style="warning" %} +`UmbracoAuthorizedApiController` has been removed from Umbraco 14. Use`ManagementApiControllerBase` class instead. + +Read the [Creating a Backoffice API article](../../tutorials/creating-a-backoffice-api/README.md) for a comprehensive guide to writing APIs for the Management API. +{% endhint %} + +Since the default media file system can be swapped with custom implementations, you should never access the implementation directly. Umbraco uses a manager class called `MediaFileManager`. You can get a reference to this manager class via dependency injection in the constructor for your custom class or controller: + +```csharp +public class ImagesController : UmbracoAuthorizedApiController +{ + private readonly MediaFileManager _mediaFileManager; + + public ImagesController(MediaFileManager mediaFileManager) + { + _mediaFileManager = mediaFileManager; + } + +{...} +``` + +You can then access the configured file system provider through `_mediaFileManager.FileSystem`, which is the same way Umbraco will access the file system provider. + +## MediaPath Scheme + +The MediaPath Scheme defines the current set of rules that decide the format of the Media Path when it is saved into the media archive wherever it is located. + +By default the MediaPath scheme used by Umbraco is the `UniqueMediaPathScheme` this generates a 'folder' to place the uploaded image in, for example: + +`/media/dozdrg2f/mylovelyimage.jpg` + +`/media` is defined by the PhysicalFileSystem and `dozdrg2f` is generated by the `UniqueMediaPathScheme`. + +{% hint style="info" %} +The folder generated by `UniqueMediaPathScheme` is not strictly unique, as it's based on the first eight characters of the GUID for the media item. In practice, with randomly generated GUIDs, a collision is unlikely. + +There is an increased possibility of generating colliding paths if creating media programmatically and setting keys using version 7 "ordered" GUIDs via `Guid.CreateVersion7()`. As such these should be avoided. `UniqueMediaPathScheme` will throw an exception if it detects they have been used. Any manually created keys should use `Guid.NewGuid()`. +{% endhint %} + +You can create your own logic for the path by implementing `IMediaPathScheme` and setting it during composition with: + +```csharp +builder.Services.AddUnique(); +``` + +## Other IFileSystems + +Umbraco also registers instances of `PhysicalFileSystem` for the following parts of Umbraco that persist to 'files': + +* `PartialViewsFileSystem` +* `StylesheetsFileSystem` +* `ScriptsFileSystem` +* `MvcViewsFileSystem` + +These are accessible via dependency injection. + +`IFileSystem`, `MediaFileManager`, and `FileSystems` are located in the `Umbraco.Cms.Core.IO` namespace. + +### Stylesheet Filesystem + +Like with the media file system it is also possible to replace the stylesheet filesystem with your own implementation of `IFileSystem` in a composer. It's important to note here that, unlike media file system, you cannot replace the filesystem with a `PhysicalFileSystem` using a different root path or root URL, this will not work, and will cause issues since the root path is coupled to the virtual path, given by the frontend, e.g. `/css/MyBeautifulStyle.css`. + +When replacing the stylesheet filesystem, you don't need to register it, since it's only available through Filesystems, what you need to do instead is configure the `FileSystems` to use your implementation for the `StylesheetsFileSystem`. + +The IUmbracoBuilder has an extension method for configuring the `FileSystems`, you need to invoke this method with an action that accepts an `IServiceProvider` and the `FileSystems` you will configure, configuring the `FileSystems` can look like this: + +```csharp +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Infrastructure.DependencyInjection; + +namespace UmbracoExamples.Composition; + +public class FileSystemComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.ConfigureFileSystems((factory, systems) => + { + IIOHelper ioHelper = factory.GetRequiredService(); + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + ILogger logger = factory.GetRequiredService>(); + GlobalSettings settings = factory.GetRequiredService>().Value; + + var path = settings.UmbracoCssPath; + var rootPath = hostingEnvironment.MapPathWebRoot(path); + var rootUrl = hostingEnvironment.ToAbsolute(path); + var fileSystem = new YourFileSystemImplementation(ioHelper, hostingEnvironment, logger, rootPath, rootUrl); + + systems.SetStylesheetFilesystem(fileSystem); + }); + } +} + +``` + +Where `YourFileSystemImplementation` is a class that implements `IFileSystem`. This should always be done in a composer, since we do not recommend trying to change filesystems on the fly. + +After the `SetStylesheetFileSystem` method has run, `FileSystems.StylesheetsFileSystem` will return the instance that was created in the `ConfigureFileSystems` extension method. + +## Custom providers + +There is an Azure Blob Storage provider: + +* [Azure Blob Storage](azure-blob-storage.md) diff --git a/17/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md b/17/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md new file mode 100644 index 00000000000..b73e5367f11 --- /dev/null +++ b/17/umbraco-cms/extending/filesystemproviders/azure-blob-storage.md @@ -0,0 +1,98 @@ +--- +description: Setup your site to use Azure Blob storage for media and ImageSharp cache +--- + +# Using Azure Blob Storage for Media and ImageSharp Cache + +There are some scenarios where you may want or need to consider leveraging Azure Blob Storage. An example would be for media in Umbraco sites with substantial media libraries. + +Having your site's media in Azure Blob Storage can help your deployments complete more quickly. This has the potential to positively affect site performance, as the ImageSharp cache is moved to Azure Blob Storage. + +The setup consists of adding a package to your site, setting the correct configuration, and adding the services and middleware. Before you begin you’ll need to create an Azure Storage Account and a container for your media and ImageSharp cache. In this example, we assume your container name is "mysitestorage" and has already been created. + +See the [Microsoft documentation](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal) for a quickstart guide on how to create a blob storage container. + +## Installing the package + +Before you begin, you need to install the `Umbraco.StorageProviders.AzureBlob` and the `Umbraco.StorageProviders.AzureBlob.ImageSharp` NuGet packages. There are two approaches to installing the packages: + +1. Use your favorite Integrated Development Environment (IDE) and open up the NuGet Package Manager to search and install the packages +2. Use the command line to install the packages + +### Installing through command line + +Navigate to your project folder, which is the folder that contains your `.csproj` file. Now use the following `dotnet add package` commands to install the packages: + +```cmd +dotnet add package Umbraco.StorageProviders.AzureBlob +dotnet add package Umbraco.StorageProviders.AzureBlob.ImageSharp +``` + +The correct packages will have been installed in your project. + +## Configuring Blob storage + +The next step is to configure your blob storage. There are multiple approaches for this, but in this document, we're going to do it through `appsettings.json`. For more configuration options, see the [readme](https://github.com/umbraco/Umbraco.StorageProviders#umbracostorageproviders) on the GitHub repository. + +Open up your `appsettings.json` file and add the connection string and container name under `Umbraco:Storage:AzureBlob:Media`. Your Umbraco section of appsettings will look something like this: + +```json + "Umbraco": { + "Storage": { + "AzureBlob": { + "Media": { + "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=;AccountKey=;EndpointSuffix=core.windows.net", + "ContainerName": "mysitestorage" + } + } + }, + "CMS": { + "Hosting": { + "Debug": false + }, + {...} + } + } +``` + +In this example, the container name is `mysitestorage`. + +{% hint style="info" %} +You can get your connection string from your Azure Portal under "Access Keys". +{% endhint %} + +## Setting the services and middleware + +You are almost there. The last step is to set up the required services and middleware. This can be done using extension methods. + +Invoke the `.AddAzureBlobMediaFileSystem()` and the `.AddAzureBlobImageSharpCache()` extension methods using the `CreateUmbracoBuilder()` builder chain in the `Program.cs` file like shown below. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddAzureBlobMediaFileSystem() // This configures the required services for Media + .AddAzureBlobImageSharpCache() // This configures the required services for the Image Sharp cache + .Build(); +``` + +Learn more about invoking and registering extension methods in the [Dependency Injection](../../reference/using-ioc.md) article. + +{% hint style="info" %} +**Upgrading from Umbraco 9/10**: + +As of [version 11.0.0](https://github.com/umbraco/Umbraco.StorageProviders/releases/tag/release-11.0.0) of `Umbraco.StorageProviders`, the ImageSharp dependency has been separated into its own package. + +Therefore, if you're planning on upgrading your site from Umbraco 9/10 to 11+, don't forget to install and setup the new `Umbraco.StorageProviders.AzureBlob.ImageSharp` package. This will ensure that your ImageSharp cache continues to be stored in your blob storage container. + +{% endhint %} + +Now when you launch your site again, the blob storage will be used to store media items as well as the ImageSharp cache. Do note though that the `/media` and `/cache` folders do not get created until a piece of media is uploaded. + +## Existing Media files + +Any media files you already have on your site will not automatically be added to the blob storage container. You will need to copy the contents on the `/wwwroot/media` folder and upload them to a new folder called `/media` in your blob storage container. Once you've done that, you can safely delete the `wwwroot/media` folder locally, as it is no longer needed. + +Any new media files you upload to the site will automatically be added to the Blob Storage. diff --git a/17/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png b/17/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png new file mode 100644 index 00000000000..a28c4f9bb7e Binary files /dev/null and b/17/umbraco-cms/extending/filesystemproviders/images/config-from-backoffice.png differ diff --git a/17/umbraco-cms/extending/health-check/README.md b/17/umbraco-cms/extending/health-check/README.md new file mode 100644 index 00000000000..2b03622e5ee --- /dev/null +++ b/17/umbraco-cms/extending/health-check/README.md @@ -0,0 +1,315 @@ +--- +description: "Health Checks are used to determine the state of your Umbraco project. Learn more about each of them in this section." +--- + +# Health Check + +The Settings section of the Umbraco backoffice holds a dashboard named "Health Check". It is a handy list of checks to see if your Umbraco installation is configured according to best practices. It's possible to add your custom-built health checks. + +For inspiration when building your checks you can look at the checks we've [built into Umbraco](https://github.com/umbraco/Umbraco-CMS/tree/v10/dev/src/Umbraco.Core/HealthChecks/Checks), as well as our [guides](guides/). Some examples will follow in this document. + +## Built-in checks + +Umbraco comes with the following checks by default: + +* Category **Configuration** + * **Notification Email Settings (id: `3E2F7B14-4B41-452B-9A30-E67FBC8E1206`)** - checks that the "from" email address used for email notifications has been changed from its default value +* Category **Data Integrity** + * **Database data integrity check (id: `73DD0C1C-E0CA-4C31-9564-1DCA509788AF`)** - checks for various data integrity issues in the Umbraco database +* Category **Live Environment** + * **Debug Compilation Mode (id: `61214FF3-FC57-4B31-B5CF-1D095C977D6D`)** - should be set to `debug="false"` on your live site + * **Runtime Mode (id: `8E31E5C9-7A1D-4ACB-A3A8-6495F3EDB932`)** - should be set to `Production` on your live site +* Category **Permissions** + * **Folder & File Permissions (id: `53DBA282-4A79-4B67-B958-B29EC40FCC23`)** - checks that the folders and files set with write permissions that are either required or recommended can be accessed +* Category **Security** + * **Application URL Configuration (id: `6708CA45-E96E-40B8-A40A-0607C1CA7F28`)** - checks if the Umbraco application URL is configured for your site. + * **Click-Jacking Protection (id: `ED0D7E40-971E-4BE8-AB6D-8CC5D0A6A5B0`)** - checks to see if a header or meta-tag is in place to indicate whether the site can be hosted in an IFRAME. Normally this is best set to deny permission for this to be done, to prevent what is known as [click-jacking](https://www.owasp.org/index.php/Clickjacking) attacks + * **Content/MIME Sniffing Protection (id: `1CF27DB3-EFC0-41D7-A1BB-EA912064E071`)** - checks that your site contains a header used to protect against Multipurpose Internet Mail Extensions (MIME) sniffing vulnerabilities + * **Cookie hijacking and protocol downgrade attacks Protection (HSTS) (id: `E2048C48-21C5-4BE1-A80B-8062162DF124`)** - checks if your HTTPS site contains the Strict-Transport-Security Header (HSTS). If not - adds with a default of 18 weeks + * **Cross-site scripting Protection (id: `F4D2B02E-28C5-4999-8463-05759FA15C3A`)** - checks for the presence of the X-XSS-Protection-header + * **Content Security Policy (CSP) (id: `10BEBF47-C128-4C5E-9680-5059BEAFBBDF`)** - checks that your site has a CSP header to defend against Cross-Site Scripting (XSS) and data injection attacks. + * **Excessive Headers (id: `92ABBAA2-0586-4089-8AE2-9A843439D577`)** - checks to ensure that various headers that can provide details about the technology used to build and host the website have been removed + * **HTTPS Configuration (id: `EB66BB3B-1BCD-4314-9531-9DA2C1D6D9A7`)** - to determine if the current site is running on a secure connection + * **UseHttps check** - when the site is running on HTTPS, `Umbraco.Cms.Core.Configuration.Models.GlobalSettings.UseHttps` needs to be enabled to secure the backoffice. The setting can be found under `Umbraco:CMS:Global` in the `appsettings.json` file +* Category **Services** + * **SMTP Settings (id: `1B5D221B-CE99-4193-97CB-5F3261EC73DF`)** - checks that an Simple Mail Transfer Protocol (SMTP) server is configured and is accepting requests for sending emails + +Each check returns a message indicating whether or not the issue in question has been found on the website installation. This could be an error that should be fixed, or a warning you should be aware of. + +Some of them can also be rectified via the dashboard, by clicking the **Fix** button and in some cases providing some required information. These changes usually involve writing to configuration files that will often trigger a restart of the website. + +## Configuring and scheduling checks + +As well as viewing the results of health checks via the Settings section dashboard, you can set up the checks to be run on a schedule and be notified of the results by email. It's also possible to disable certain checks if they aren't applicable in your environment. + +For more information, see the [Reference > Configuration > Health checks](../../reference/configuration/healthchecks.md) article. + +## Custom checks + +You can build your own health checks. There are two types of health checks you can build: **configuration checks** and **general checks**. + +Each health check is a class that needs to have a `HealthCheck` attribute. This attribute has a few things you need to fill in: + +* GUID - a unique ID that you've generated for this specific check +* Name - give it a short name so people know what the check is for +* Description - describes what the check does in detail +* Group - this is the category for the check if you use an existing group name (like "Configuration") the check will be added in that category, otherwise a new category will appear in the dashboard + +### Configuration checks + +These are small checks that take an [IConfiguration](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.iconfiguration?view=dotnet-plat-ext-6.0) key and confirm that the value that's expected is there. If the value is not correct, there will be a link to a guide on how to set this value correct. + +* A configuration check needs to inherit from `Umbraco.Cms.Core.HealthChecks.Checks.AbstractSettingsCheck` +* A configuration check needs the `HealthCheck` attribute as noted at the start of this document +* `ReadMoreLink` is a link to an external guide that will help you to troubleshoot any problems +* `ValueComparisonType` can either be `ValueComparisonType.ShouldEqual` or `ValueComparisonType.ShouldNotEqual` +* `ItemPath` is the IConfiguration key path leading to the configuration value that you want to verify +* `Values` is a list of values that are available for this configuration item - in this example it can be `RemoteOnly` or `On`, they're both acceptable for a live site. + * For checks using the `ShouldEqual` comparison method, make sure to set one of these values to `IsRecommended = true`. + * Where `ShouldNotEqual` is used the fix will require the user to provide the correct setting +* `CurrentValue` is the current value from the configuration setting +* `CheckSuccessMessage` and `CheckErrorMessage` are the messages returned to the user + * It is highly recommended to use the `LocalizedTextService` so these can be localized. You can add the text in `~/Config/Lang/en-US.user.xml` (or whatever language you like) + +### General checks + +This can be anything you can think of, the results and the rectify action are completely under your control. + +* A general check needs to inherit from `Umbraco.Cms.Core.HealthChecks.HealthCheck` +* A general check needs the `HealthCheck` attribute as noted at the start of this document +* All checks run when the dashboard is loaded, this means that the `GetStatus()` method gets executed + * You can return multiple status checks from `GetStatus()` +* A status check returns a `HealthCheckStatus` + * If a `HealthCheckStatus` has a `HealthCheckAction` defined then the "Fix" button will perform that action once clicked + * Sometimes, the button to fix something should not be called "Fix", change the `Name` property of a `HealthCheckAction` to provide a better name + * `HealthCheckAction` has a `Description` property so that you can provide information on what clicking the "Rectify" button will do (or provide links to documentation, for example) + * `HealthCheckStatus` has a few result levels: + * `StatusResultType.Success` + * `StatusResultType.Error` + * `StatusResultType.Warning` + * `StatusResultType.Info` + * A `HealthCheckAction` needs to provide an alias for an action that can be picked up in the `ExecuteAction` method +* It is highly recommended to use the `LocalizedTextService` so text can be localized. You can add the text in `~/Config/Lang/en-US.user.xml` (or whatever language you like) + +An example check: + +```csharp +using Umbraco.Cms.Core.Extensions; +using Umbraco.Cms.Core.HealthChecks; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Web.HealthCheck.Checks.SEO; + +[HealthCheck("3A482719-3D90-4BC1-B9F8-910CD9CF5B32", "Robots.txt", + Description = "Create a robots.txt file to block access to system folders.", + Group = "SEO")] +public class HealthCheckNotifier : Cms.Core.HealthChecks.HealthCheck +{ + private readonly IHostEnvironment _hostEnvironment; + private readonly ILogger _logger; + private readonly ILocalizedTextService _textService; + + public HealthCheckNotifier(ILocalizedTextService textService, IHostEnvironment hostEnvironment, + ILogger logger) + { + _textService = textService; + _hostEnvironment = hostEnvironment; + _logger = logger; + } + + public override Task> GetStatus() => + Task.FromResult((IEnumerable)new[] { CheckForRobotsTxtFile() }); + + public override HealthCheckStatus ExecuteAction(HealthCheckAction action) + { + switch (action.Alias) + { + case "addDefaultRobotsTxtFile": + return AddDefaultRobotsTxtFile(); + default: + throw new InvalidOperationException("Action not supported"); + } + } + + private HealthCheckStatus CheckForRobotsTxtFile() + { + var success = File.Exists(_hostEnvironment.MapPathContentRoot("~/robots.txt")); + var message = success + ? _textService.Localize("healthcheck", "seoRobotsCheckSuccess") + : _textService.Localize("healthcheck", "seoRobotsCheckFailed"); + + var actions = new List(); + + if (success == false) + { + actions.Add(new HealthCheckAction("addDefaultRobotsTxtFile", Id) + // Override the "Rectify" button name and describe what this action will do + { + Name = _textService.Localize("healthcheck", "seoRobotsRectifyButtonName"), + Description = _textService.Localize("healthcheck", "seoRobotsRectifyDescription") + }); + } + + return + new HealthCheckStatus(message) + { + ResultType = success ? StatusResultType.Success : StatusResultType.Error, + Actions = actions + }; + } + + private HealthCheckStatus AddDefaultRobotsTxtFile() + { + var success = false; + var message = string.Empty; + const string content = @"# robots.txt for Umbraco +User-agent: * +Disallow: /umbraco/"; + + try + { + File.WriteAllText(_hostEnvironment.MapPathContentRoot("~/robots.txt"), content); + success = true; + } + catch (Exception exception) + { + _logger.LogError(exception, "Could not write robots.txt to the root of the site"); + } + + return + new HealthCheckStatus(message) + { + ResultType = success ? StatusResultType.Success : StatusResultType.Error, + Actions = new List() + }; + } +} +``` + +## Custom health check notifications + +Health check notifications can be scheduled to run periodically and notify you of the results. Included with Umbraco is a notification method to deliver the results via email. In a similar manner to how it's possible to create your health checks, you can also create custom notification methods to send the message summarising the status of the health checks via other means. Again, for further details on implementing this please refer to the [existing notification methods within the core code base](https://github.com/umbraco/Umbraco-CMS/tree/v10/dev/src/Umbraco.Core/HealthChecks/NotificationMethods). + +Each notification method needs to implement the core interface `IHealthCheckNotificationMethod` and, for ease of creation, can inherit from the base class `NotificationMethodBase`, which itself implements the `IHealthCheckNotificationMethod` interface. The class must also be decorated with an instance of the `HealthCheckNotificationMethod` attribute. There's one method to implement - `SendAsync(HealthCheckResults results)` - which is responsible for taking the results of the health checks and sending them via the mechanism of your choice. + +The following example shows how the core method for sending notification via email is implemented: + +```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Mail; +using Umbraco.Cms.Core.Models.Email; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Core.HealthChecks.NotificationMethods; + +[HealthCheckNotificationMethod("email")] +public class EmailNotificationMethod : NotificationMethodBase +{ + private readonly ILocalizedTextService? _textService; + private readonly IHostEnvironment? _hostEnvironment; + private readonly IEmailSender? _emailSender; + private readonly IMarkdownToHtmlConverter? _markdownToHtmlConverter; + private ContentSettings? _contentSettings; + + public EmailNotificationMethod( + ILocalizedTextService textService, + IHostEnvironment hostEnvironment, + IEmailSender emailSender, + IOptionsMonitor healthChecksSettings, + IOptionsMonitor contentSettings, + IMarkdownToHtmlConverter markdownToHtmlConverter) + : base(healthChecksSettings) + { + var recipientEmail = Settings?["RecipientEmail"]; + if (string.IsNullOrWhiteSpace(recipientEmail)) + { + Enabled = false; + return; + } + + RecipientEmail = recipientEmail; + + _textService = textService ?? throw new ArgumentNullException(nameof(textService)); + _hostEnvironment = hostEnvironment; + _emailSender = emailSender; + _markdownToHtmlConverter = markdownToHtmlConverter; + _contentSettings = contentSettings.CurrentValue ?? throw new ArgumentNullException(nameof(contentSettings)); + + contentSettings.OnChange(x => _contentSettings = x); + } + + public string? RecipientEmail { get; } + + public override async Task SendAsync(HealthCheckResults results) + { + if (ShouldSend(results) == false) + { + return; + } + + if (string.IsNullOrEmpty(RecipientEmail)) + { + return; + } + + var message = _textService?.Localize("healthcheck", "scheduledHealthCheckEmailBody", new[] + { + DateTime.Now.ToShortDateString(), + DateTime.Now.ToShortTimeString(), + _markdownToHtmlConverter?.ToHtml(results, Verbosity) + }); + + // Include the Umbraco Application URL host in the message subject so that + // you can identify the site that these results are for. + var host = _hostEnvironment?.ContentRootPath?.ToString(); + + var subject = _textService?.Localize("healthcheck", "scheduledHealthCheckEmailSubject", new[] { host }); + + + var mailMessage = CreateMailMessage(subject, message); + Task? task = _emailSender?.SendAsync(mailMessage, Constants.Web.EmailTypes.HealthCheck); + if (task is not null) + { + await task; + } + } + + private EmailMessage CreateMailMessage(string? subject, string? message) + { + var to = _contentSettings?.Notifications.Email; + + if (string.IsNullOrWhiteSpace(subject)) + subject = "Umbraco Health Check Status"; + + var isBodyHtml = message.IsNullOrWhiteSpace() == false && message!.Contains("<") && message.Contains(" options.SameOrigin()); +``` + +### Adding Click-Jacking Protection using manual middleware + +Avoid third-party library dependency by using custom middleware added to the request pipeline. + +```csharp +app.Use(async (context, next) => +{ + context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN"); + await next(); +}); +``` diff --git a/17/umbraco-cms/extending/health-check/guides/contentsecuritypolicy.md b/17/umbraco-cms/extending/health-check/guides/contentsecuritypolicy.md new file mode 100644 index 00000000000..055d41d1292 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/contentsecuritypolicy.md @@ -0,0 +1,54 @@ +--- +description: Implement a Content Security Policy (CSP) to protect your Umbraco site from XSS and data injection. +--- + +# Content Security Policy (CSP) + +_This check verifies if your site has a Content Security Policy (CSP) header to defend against Cross-Site Scripting (XSS) and data injection attacks._ + +## How to fix this health check +This health check can be fixed by adding a header before the response is started. + +Preferable you use a security library like [NWebSec](https://docs.nwebsec.com/). + +### Adding a Content Security Policy (CSP) using NWebSec + +If you take a NuGet dependency on [NWebsec.AspNetCore.Middleware/](https://www.nuget.org/packages/NWebsec.AspNetCore.Middleware/), you can use third extension methods on `IApplicationBuilder`. + +```csharp +... +WebApplication app = builder.Build(); +app.UseCsp(options => options + .ImageSources(s => s + .Self() + .CustomSources( + "our.umbraco.com data:", + "dashboard.umbraco.com")) + .DefaultSources(s => s + .Self() + .CustomSources( + "our.umbraco.com", + "marketplace.umbraco.com")) + .ScriptSources(s => s + .Self()) + .StyleSources(s => s + .Self()) + .FontSources(s => s + .Self()) + .ConnectSources(s => s + .Self()) + .FrameSources(s => s + .Self())); +``` + +### Adding a Content Security Policy (CSP) using manual middleware + +Avoid third-party library dependencies by using custom middleware added to the request pipeline as shown below. + +```csharp +app.Use(async (context, next) => +{ + context.Response.Headers.Append("Content-Security-Policy", "img-src 'self' our.umbraco.com data: dashboard.umbraco.com; default-src 'self' our.umbraco.com marketplace.umbraco.com; script-src 'self'; style-src 'unsafe-inline' 'self'; font-src 'self'; connect-src 'self'; frame-src 'self'; "); + await next(); +}); +``` \ No newline at end of file diff --git a/17/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md b/17/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md new file mode 100644 index 00000000000..ae71f98a164 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/contentsniffingprotection.md @@ -0,0 +1,68 @@ +--- +description: Protect your Umbraco site from MIME sniffing vulnerabilities using security headers like X-Content-Type-Options. +--- + +# Health check: Content/MIME Sniffing Protection + +_Checks that your site contains a header used to protect against Multipurpose Internet Mail Extensions (MIME) sniffing vulnerabilities._ + +## How to fix this health check + +This health check can be fixed by adding a header before the response is started. + +Preferable you use a security library like [NWebSec](https://docs.nwebsec.com/). + +### Adding Content/MIME Sniffing Protection using NWebSec + +If you take a NuGet dependency on [NWebsec.AspNetCore.Middleware/](https://www.nuget.org/packages/NWebsec.AspNetCore.Middleware/), you can use third extension methods on `WebApplication`. + +```csharp +... +WebApplication app = builder.Build(); + +app.UseXContentTypeOptions(); +... +``` + +### Adding Content/MIME Sniffing Protection using manual middleware + +If you do not like to have a dependency on third party libraries, you can add the following custom middleware to the request pipeline. + +First create the middleware class: + +```csharp +namespace MySite.Middleware; + +public class NoSniffMiddleware : IMiddleware +{ + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + context.Response.Headers.Append("X-Content-Type-Options", "nosniff"); + await next(context); + } +} +``` + +Next register it in `Program.cs` + +```csharp +using MySite.Middleware; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +builder.Services.AddSingleton(); + +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .Build(); + +WebApplication app = builder.Build(); + +app.UseMiddleware(); + +await app.BootUmbracoAsync(); +... +``` diff --git a/17/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md b/17/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md new file mode 100644 index 00000000000..691135931ab --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/crosssitescriptingprotection.md @@ -0,0 +1,11 @@ +# Health check: Cross-site scripting Protection (X-XSS-Protection header) + +{% hint style="warning" %} +This header is non-standard and should not be used. Instead, it is recommended to use a [Content Security Policy (CSP)](./contentsecuritypolicy.md) header. + +For more information about the X-XSS-Protection header, and why it should not be used, see [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection). +{% endhint %} + +## How to fix this health check + +This health check can be fixed by ensuring no middleware adds the header. diff --git a/17/umbraco-cms/extending/health-check/guides/debugcompilationmode.md b/17/umbraco-cms/extending/health-check/guides/debugcompilationmode.md new file mode 100644 index 00000000000..8395c9e09da --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/debugcompilationmode.md @@ -0,0 +1,43 @@ +--- +description: Disable debug compilation mode in Umbraco to boost performance by updating JSON configuration. +--- + +# Health check: Debug Compilation Mode + +_Leaving debug compilation mode enabled can severely slow down a website and take up more memory on the server._ + +## How to fix this health check + +This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Hosting:Debug`. + +This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. + +### Updating the JSON configuration + +The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. + +```json +{ + "Umbraco": { + "CMS": { + "Hosting": { + "Debug": + } + } + } +} +``` + +One example that can be used for production: + +```json +{ + "Umbraco": { + "CMS": { + "Hosting": { + "Debug": false + } + } + } +} +``` diff --git a/17/umbraco-cms/extending/health-check/guides/excessiveheaders.md b/17/umbraco-cms/extending/health-check/guides/excessiveheaders.md new file mode 100644 index 00000000000..bbab463ba86 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/excessiveheaders.md @@ -0,0 +1,46 @@ +# Health check: Excessive Headers + +_Checks to see if your site reveals information in its headers that gives away unnecessary details about the technology used to build and host it._ + +## How to fix this health check + +This health check can be fixed by removing headers before the response is started. + +Be aware these headers are often added by the server and not by the application. + +Unless you publicly expose the Kestrel server ([not recommended by Microsoft](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.1&tabs=aspnetcore2x#when-to-use-kestrel-with-a-reverse-proxy)), you can't handle this directly in middleware. + +### Removing headers when hosted on IIS + +For IIS you will need to manipulate `web.config` (If you don't have `web.config` already in your project you will need to add it at the root). Ensure to remove the custom `X-Powered-By` and `Server` header as shown in the following example. + +{% hint style="info" %} +The `removeServerHeader` attribute is added in IIS 10.0 and does not work in versions of Windows prior to Windows Server version 1709 or Windows 10 version 1709. +{% endhint %} + +```xml + + + + + + + + + + + + + +``` + +### Removing headers when hosted on Kestrel + +By default Kestrel will only expose the `Server` header. To disable this, you have to configure Kestrel in `Program.cs`. You can use the `UseKestrel` extension method on `WebApplicationBuilder` like in the following example. + +```csharp +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +builder.WebHost.UseKestrel(options => options.AddServerHeader = false); +... +``` diff --git a/17/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md b/17/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md new file mode 100644 index 00000000000..b96de969184 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/fixedapplicationurl.md @@ -0,0 +1,44 @@ +# Fixed Application Url + +_Check to make sure a fixed application URL is specified. This URL is for example used when sending emails from backoffice._\ +&#xNAN;_If this is not specified in configuration, Umbraco gets the application URL from last host used to request the application_ + +## How to fix this health check + +This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:WebRouting:UmbracoApplicationUrl`. + +This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. + +### Updating the JSON configuration + +The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. + +```json +{ + "Umbraco": { + "CMS": { + "WebRouting": { + "UmbracoApplicationUrl": "string" + } + } + } +} +``` + +One example that can be used in production + +```json +{ + "Umbraco": { + "CMS": { + "WebRouting": { + "UmbracoApplicationUrl": "https://www.my-custom-domain.com/" + } + } + } +} +``` + +{% hint style="info" %} +If the site is hosted on Umbraco Cloud, changing the above configuration will have no effect. The site will always use the URL set in the\`umbraco-cloud.json\` file, which can not be changed. +{% endhint %} diff --git a/17/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md b/17/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md new file mode 100644 index 00000000000..95dd3ded7e0 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/folderandfilepermissions.md @@ -0,0 +1,25 @@ +# Folder & File Permissions + +_Checks that the web server folder and file permissions are set correctly for Umbraco to run._ + +## How to fix this health check + +This health check can be fixed by ensuring that the process running Umbraco also has write access to the listed folders and files. + +### Updating the file permissions on Windows + +Here's an example of how to adjust permissions for a folder. This process works the same way for files. + +First we see an example of an error from the health check + +![Failed health check for folder creation](images/failed\_healthcheck\_folder\_permissions.png) + +To fix this, we find the specified folder, from the report and choose `Properties` and the `Security` tab. + +![Folder properties](images/folder\_properties.png) ![Folder properties - Security tab](images/folder\_properties\_security.png) + +From here you can edit the permissions for a specific user or user group. + +{% hint style="info" %} +For security reasons we recommend only giving write access to the required users or groups. +{% endhint %} diff --git a/17/umbraco-cms/extending/health-check/guides/httpsconfiguration.md b/17/umbraco-cms/extending/health-check/guides/httpsconfiguration.md new file mode 100644 index 00000000000..e96bd7b1a83 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/httpsconfiguration.md @@ -0,0 +1,43 @@ +# Health check: HTTPS Configuration + +_Checks if your site is configured to work over HTTPS and if the Umbraco related configuration for that is correct._ + +## How to fix this health check + +This health check checks a couple of things. + +First of all, it ensures that your website is running on HTTPS using a valid certificate. + +Furthermore, it is used to specify the configuration on the following path: `Umbraco:CMS:Global:UseHttps`. + +This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. + +### Updating the JSON configuration + +The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. + +```json +{ + "Umbraco": { + "CMS": { + "Global": { + "UseHttps": + } + } + } +} +``` + +One example that can be used: + +```json +{ + "Umbraco": { + "CMS": { + "Global": { + "UseHttps": true + } + } + } +} +``` diff --git a/17/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png b/17/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png new file mode 100644 index 00000000000..6dc15b3c5af Binary files /dev/null and b/17/umbraco-cms/extending/health-check/guides/images/failed_healthcheck_folder_permissions.png differ diff --git a/17/umbraco-cms/extending/health-check/guides/images/folder_properties.png b/17/umbraco-cms/extending/health-check/guides/images/folder_properties.png new file mode 100644 index 00000000000..871cf463060 Binary files /dev/null and b/17/umbraco-cms/extending/health-check/guides/images/folder_properties.png differ diff --git a/17/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png b/17/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png new file mode 100644 index 00000000000..79a3fc7122e Binary files /dev/null and b/17/umbraco-cms/extending/health-check/guides/images/folder_properties_security.png differ diff --git a/17/umbraco-cms/extending/health-check/guides/notificationemail.md b/17/umbraco-cms/extending/health-check/guides/notificationemail.md new file mode 100644 index 00000000000..3ecbe7747fb --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/notificationemail.md @@ -0,0 +1,43 @@ +# Health check: Notification Email Settings + +_If notifications are used, the 'from' email address should be specified and changed from the default value._ + +## How to fix this health check + +This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Content:Notifications:Email`. + +This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. + +### Updating the JSON configuration + +The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. + +```json +{ + "Umbraco": { + "CMS": { + "Content": { + "Notifications": { + "Email": "" + } + } + } + } +} +``` + +One example that can be used: + +```json +{ + "Umbraco": { + "CMS": { + "Content": { + "Notifications": { + "Email": "no-reply@domain.com" + } + } + } + } +} +``` diff --git a/17/umbraco-cms/extending/health-check/guides/smtp.md b/17/umbraco-cms/extending/health-check/guides/smtp.md new file mode 100644 index 00000000000..8fce916f7b5 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/smtp.md @@ -0,0 +1,52 @@ +# Health check: SMTP + +_Checks that valid settings for sending emails are in place._ + +## How to fix this health check + +This health check can be fixed by providing configuration on the following path: `Umbraco:CMS:Global:Smtp` + +This configuration can be setup in a configuration source of your choice. This guide shows how to set it up in one of the JSON file sources. + +### Updating the JSON configuration + +The following JSON needs to be merged into one of your JSON sources. By default the following JSON sources are used: `appSettings.json` and `appSettings..json`, e.g. `appSettings.Development.json` or `appSettings.Production.json`. + +```json +{ + "Umbraco": { + "CMS": { + "Global": { + "Smtp": { + "From": "", + "Host": "", + "Port": , + "PickupDirectoryLocation": "", + "Username": "", + "Password": "", + "DeliveryMethod": "", + "SecureSocketOptions": "" + } + } + } + } +} +``` + +An example that can be used on localhost, is if you have a local Simple Mail Transfer Protocol (SMTP) server running during development. This could be a tool like [Smtp4dev](https://github.com/rnwood/smtp4dev). + +```json +{ + "Umbraco": { + "CMS": { + "Global": { + "Smtp": { + "From": "my@email.com", + "Host": "localhost", + "Port": 25 + } + } + } + } +} +``` diff --git a/17/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md b/17/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md new file mode 100644 index 00000000000..72cea315e11 --- /dev/null +++ b/17/umbraco-cms/extending/health-check/guides/stricttransportsecurityheader.md @@ -0,0 +1,40 @@ +--- +description: "Learn about the health checks that check for cookie hijacking and protocol downgrade attacks protection." +--- + +# Strict-Transport-Security Header + +Checks if your site, when running with HTTPS, contains the Strict-Transport-Security Header (HSTS). + +## How to fix this health check + +This health check can be fixed by adding the `Strict-Transport-Security` header to responses. The header tells browsers that future requests should be made over HTTPS only. + +{% hint style="warning" %} +Enabling HSTS on a domain will cause browsers to only use HTTPS (not HTTP) to communicate with your site. Only enable HSTS on domains that can, and should, use HTTPS exclusively. +{% endhint %} + +### Using the UseHsts extension method + +ASP.NET Core implements HSTS with the `UseHsts` extension method. + +You can add `UseHsts` after the `env.IsDevelopment()` check-in `Program.cs`. + +```csharp +if (builder.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} +else +{ + app.UseHsts(); +} + //... +} +``` + +This example only enables HSTS if the app is not running in development mode. `UseHsts` isn't recommended in development because the HSTS settings are highly cacheable by browsers. + +It is possible to configure a timespan for the HSTS, preferably six months. This can be done by adding a new builder to the `Program.cs` file. Learn more in the [official Microsoft Documentation](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-8.0&tabs=visual-studio%2Clinux-ubuntu#http-strict-transport-security-protocol-hsts). + +Full details of `UseHsts`, and additional configuration, can be found in the [ASP.NET Core documentation](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-8.0&tabs=visual-studio%2Clinux-ubuntu#http-strict-transport-security-protocol-hsts). diff --git a/17/umbraco-cms/extending/images/Canvas_tab (1).png b/17/umbraco-cms/extending/images/Canvas_tab (1).png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/extending/images/Canvas_tab (1).png differ diff --git a/17/umbraco-cms/extending/images/Canvas_tab (2).png b/17/umbraco-cms/extending/images/Canvas_tab (2).png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/extending/images/Canvas_tab (2).png differ diff --git a/17/umbraco-cms/extending/images/Canvas_tab.png b/17/umbraco-cms/extending/images/Canvas_tab.png new file mode 100644 index 00000000000..1e6b0c0730a Binary files /dev/null and b/17/umbraco-cms/extending/images/Canvas_tab.png differ diff --git a/17/umbraco-cms/extending/images/Docs_tab (1).png b/17/umbraco-cms/extending/images/Docs_tab (1).png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/extending/images/Docs_tab (1).png differ diff --git a/17/umbraco-cms/extending/images/Docs_tab (2).png b/17/umbraco-cms/extending/images/Docs_tab (2).png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/extending/images/Docs_tab (2).png differ diff --git a/17/umbraco-cms/extending/images/Docs_tab.png b/17/umbraco-cms/extending/images/Docs_tab.png new file mode 100644 index 00000000000..ac21325f172 Binary files /dev/null and b/17/umbraco-cms/extending/images/Docs_tab.png differ diff --git a/17/umbraco-cms/extending/images/Embed-Button.png b/17/umbraco-cms/extending/images/Embed-Button.png new file mode 100644 index 00000000000..c52341893ad Binary files /dev/null and b/17/umbraco-cms/extending/images/Embed-Button.png differ diff --git a/17/umbraco-cms/extending/images/Embed-YouTube.png b/17/umbraco-cms/extending/images/Embed-YouTube.png new file mode 100644 index 00000000000..ae6456c438c Binary files /dev/null and b/17/umbraco-cms/extending/images/Embed-YouTube.png differ diff --git a/17/umbraco-cms/extending/images/content-app-1.png b/17/umbraco-cms/extending/images/content-app-1.png new file mode 100644 index 00000000000..ffae7300253 Binary files /dev/null and b/17/umbraco-cms/extending/images/content-app-1.png differ diff --git a/17/umbraco-cms/extending/images/content-app-2.png b/17/umbraco-cms/extending/images/content-app-2.png new file mode 100644 index 00000000000..b3b479c6c3c Binary files /dev/null and b/17/umbraco-cms/extending/images/content-app-2.png differ diff --git a/17/umbraco-cms/extending/images/content-app-badge-v9.png b/17/umbraco-cms/extending/images/content-app-badge-v9.png new file mode 100644 index 00000000000..7afd0e57dc3 Binary files /dev/null and b/17/umbraco-cms/extending/images/content-app-badge-v9.png differ diff --git a/17/umbraco-cms/extending/images/content-app-badge.png b/17/umbraco-cms/extending/images/content-app-badge.png new file mode 100644 index 00000000000..80d3b00631e Binary files /dev/null and b/17/umbraco-cms/extending/images/content-app-badge.png differ diff --git a/17/umbraco-cms/extending/images/content-apps-location.png b/17/umbraco-cms/extending/images/content-apps-location.png new file mode 100644 index 00000000000..7192d228876 Binary files /dev/null and b/17/umbraco-cms/extending/images/content-apps-location.png differ diff --git a/17/umbraco-cms/extending/images/content-dashboards.png b/17/umbraco-cms/extending/images/content-dashboards.png new file mode 100644 index 00000000000..f2ef027c2e8 Binary files /dev/null and b/17/umbraco-cms/extending/images/content-dashboards.png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (1).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (1).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (1).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (2).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (2).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (2).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (3).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (3).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1) (3).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (1).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (2).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (2).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1) (2).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8 (1).png b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1).png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8 (1).png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific-v8.png b/17/umbraco-cms/extending/images/contentTypespecific-v8.png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific-v8.png differ diff --git a/17/umbraco-cms/extending/images/contentTypespecific.png b/17/umbraco-cms/extending/images/contentTypespecific.png new file mode 100644 index 00000000000..06cfabb8035 Binary files /dev/null and b/17/umbraco-cms/extending/images/contentTypespecific.png differ diff --git a/17/umbraco-cms/extending/images/db-table (1).png b/17/umbraco-cms/extending/images/db-table (1).png new file mode 100644 index 00000000000..f5bae665216 Binary files /dev/null and b/17/umbraco-cms/extending/images/db-table (1).png differ diff --git a/17/umbraco-cms/extending/images/db-table (2).png b/17/umbraco-cms/extending/images/db-table (2).png new file mode 100644 index 00000000000..f5bae665216 Binary files /dev/null and b/17/umbraco-cms/extending/images/db-table (2).png differ diff --git a/17/umbraco-cms/extending/images/db-table.png b/17/umbraco-cms/extending/images/db-table.png new file mode 100644 index 00000000000..f5bae665216 Binary files /dev/null and b/17/umbraco-cms/extending/images/db-table.png differ diff --git a/17/umbraco-cms/extending/images/developer-dashboards.png b/17/umbraco-cms/extending/images/developer-dashboards.png new file mode 100644 index 00000000000..1304c5c1805 Binary files /dev/null and b/17/umbraco-cms/extending/images/developer-dashboards.png differ diff --git a/17/umbraco-cms/extending/images/deviantart-embedded-media.png b/17/umbraco-cms/extending/images/deviantart-embedded-media.png new file mode 100644 index 00000000000..ca8a8902ac1 Binary files /dev/null and b/17/umbraco-cms/extending/images/deviantart-embedded-media.png differ diff --git a/17/umbraco-cms/extending/images/element-v8.png b/17/umbraco-cms/extending/images/element-v8.png new file mode 100644 index 00000000000..878ce70c25b Binary files /dev/null and b/17/umbraco-cms/extending/images/element-v8.png differ diff --git a/17/umbraco-cms/extending/images/element.png b/17/umbraco-cms/extending/images/element.png new file mode 100644 index 00000000000..75bdeea01cc Binary files /dev/null and b/17/umbraco-cms/extending/images/element.png differ diff --git a/17/umbraco-cms/extending/images/getting-started-dashboard.jpg b/17/umbraco-cms/extending/images/getting-started-dashboard.jpg new file mode 100644 index 00000000000..3af5f1808e3 Binary files /dev/null and b/17/umbraco-cms/extending/images/getting-started-dashboard.jpg differ diff --git a/17/umbraco-cms/extending/images/image-position-v8.png b/17/umbraco-cms/extending/images/image-position-v8.png new file mode 100644 index 00000000000..7a9995081f5 Binary files /dev/null and b/17/umbraco-cms/extending/images/image-position-v8.png differ diff --git a/17/umbraco-cms/extending/images/image-position.png b/17/umbraco-cms/extending/images/image-position.png new file mode 100644 index 00000000000..f6b86300305 Binary files /dev/null and b/17/umbraco-cms/extending/images/image-position.png differ diff --git a/17/umbraco-cms/extending/images/introstep.png b/17/umbraco-cms/extending/images/introstep.png new file mode 100644 index 00000000000..ca631766a82 Binary files /dev/null and b/17/umbraco-cms/extending/images/introstep.png differ diff --git a/17/umbraco-cms/extending/images/step-event-element-v8.png b/17/umbraco-cms/extending/images/step-event-element-v8.png new file mode 100644 index 00000000000..185991d1530 Binary files /dev/null and b/17/umbraco-cms/extending/images/step-event-element-v8.png differ diff --git a/17/umbraco-cms/extending/images/step-event-element.png b/17/umbraco-cms/extending/images/step-event-element.png new file mode 100644 index 00000000000..fb12fee4e39 Binary files /dev/null and b/17/umbraco-cms/extending/images/step-event-element.png differ diff --git a/17/umbraco-cms/extending/images/stepcontent-v8.png b/17/umbraco-cms/extending/images/stepcontent-v8.png new file mode 100644 index 00000000000..cf0776b57d0 Binary files /dev/null and b/17/umbraco-cms/extending/images/stepcontent-v8.png differ diff --git a/17/umbraco-cms/extending/images/stepcontent.png b/17/umbraco-cms/extending/images/stepcontent.png new file mode 100644 index 00000000000..adbe84d994a Binary files /dev/null and b/17/umbraco-cms/extending/images/stepcontent.png differ diff --git a/17/umbraco-cms/extending/images/steptitle-v8.png b/17/umbraco-cms/extending/images/steptitle-v8.png new file mode 100644 index 00000000000..522e3008c1a Binary files /dev/null and b/17/umbraco-cms/extending/images/steptitle-v8.png differ diff --git a/17/umbraco-cms/extending/images/steptitle.png b/17/umbraco-cms/extending/images/steptitle.png new file mode 100644 index 00000000000..c3ea636c953 Binary files /dev/null and b/17/umbraco-cms/extending/images/steptitle.png differ diff --git a/17/umbraco-cms/extending/images/the-dashboard-package.png b/17/umbraco-cms/extending/images/the-dashboard-package.png new file mode 100644 index 00000000000..e565eea3cf4 Binary files /dev/null and b/17/umbraco-cms/extending/images/the-dashboard-package.png differ diff --git a/17/umbraco-cms/extending/images/tourallowdisable-v8.png b/17/umbraco-cms/extending/images/tourallowdisable-v8.png new file mode 100644 index 00000000000..ba501f4fd87 Binary files /dev/null and b/17/umbraco-cms/extending/images/tourallowdisable-v8.png differ diff --git a/17/umbraco-cms/extending/images/tourallowdisable.png b/17/umbraco-cms/extending/images/tourallowdisable.png new file mode 100644 index 00000000000..7d24eae70e6 Binary files /dev/null and b/17/umbraco-cms/extending/images/tourallowdisable.png differ diff --git a/17/umbraco-cms/extending/images/tourgroup-v8.png b/17/umbraco-cms/extending/images/tourgroup-v8.png new file mode 100644 index 00000000000..b2a4a7efb38 Binary files /dev/null and b/17/umbraco-cms/extending/images/tourgroup-v8.png differ diff --git a/17/umbraco-cms/extending/images/tourgroup.png b/17/umbraco-cms/extending/images/tourgroup.png new file mode 100644 index 00000000000..2509c199dba Binary files /dev/null and b/17/umbraco-cms/extending/images/tourgroup.png differ diff --git a/17/umbraco-cms/extending/images/tourname-v8.png b/17/umbraco-cms/extending/images/tourname-v8.png new file mode 100644 index 00000000000..e247687d244 Binary files /dev/null and b/17/umbraco-cms/extending/images/tourname-v8.png differ diff --git a/17/umbraco-cms/extending/images/tourname.png b/17/umbraco-cms/extending/images/tourname.png new file mode 100644 index 00000000000..91466067eb7 Binary files /dev/null and b/17/umbraco-cms/extending/images/tourname.png differ diff --git a/17/umbraco-cms/extending/images/welcome-dashboard.jpg b/17/umbraco-cms/extending/images/welcome-dashboard.jpg new file mode 100644 index 00000000000..60c31089586 Binary files /dev/null and b/17/umbraco-cms/extending/images/welcome-dashboard.jpg differ diff --git a/17/umbraco-cms/extending/key-vault.md b/17/umbraco-cms/extending/key-vault.md new file mode 100644 index 00000000000..d0e00cc0780 --- /dev/null +++ b/17/umbraco-cms/extending/key-vault.md @@ -0,0 +1,260 @@ +--- +description: A guide for configuring Azure Key Vault +--- + +# Configuring Azure Key Vault + +From a security perspective, storing your application secrets in Azure Key Vault is always a good solution. This could be a connection string or other keys. + +This article tells you how to configure your application so it is ready to use a Key Vault. + +Depending on your hosting situation there are a few approaches to incorporating Azure Key Vault into your application. + +1. [Install Key Vault via Nuget (for most Hosting scenarios)](key-vault.md#install-key-vault-via-nuget) +2. [Use Key Vault references for Azure App Service (For Azure Web App Hosting)](key-vault.md#use-key-vault-references-for-azure-app-service) + +## Install Key Vault via Nuget + +Before you begin, you need to install the `Azure.Extensions.AspNetCore.Configuration.Secrets` and the `Azure.Identity` NuGet packages. There are two approaches to installing the packages: + +1. Use your favorite Integrated Development Environment (IDE) and open up the NuGet Package Manager to search and install the packages +2. Use the command line to install the package + +### Installing through command line + +Navigate to your project folder, which is the folder that contains your `.csproj` file. Now use the following `dotnet add package` command to install the packages: + +``` +dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets +dotnet add package Azure.Identity +``` + +### Configuration + +{% hint style="info" %} +You can find the database connection string under the `Umbraco:CMS:ConnectionStrings` section in the `appsettings.json` file. For more information, see the [Connection strings settings](../reference/configuration/connectionstringssettings.md) article. +{% endhint %} + +The next step is to add the Azure Key Vault endpoint to the `appsettings.json` file (or create as an Environment Variable). You can add this endpoint in the root or anywhere in the `appsettings.json` as long as it is resolved in the `ConfigureAppConfiguration` method. + +```json +{ + "AzureKeyVaultEndpoint": "https://{your-key-vault-name}.vault.azure.net", +} +``` + +After adding the endpoint in the appsettings, it's time to add configuration so that the KeyVault is used. One way to achieve this is to write an extension method for the `WebApplicationBuilder`: + +```csharp +using System; +using Azure.Identity; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Extensions; + +namespace My.Website; + +public static class WebApplicationBuilderExtensions +{ + public static WebApplicationBuilder ConfigureKeyVault(this WebApplicationBuilder builder) + { + var keyVaultEndpoint = builder.Configuration["AzureKeyVaultEndpoint"]; + if (!string.IsNullOrWhiteSpace(keyVaultEndpoint) && Uri.TryCreate(keyVaultEndpoint, UriKind.Absolute, out var validUri)) + { + builder.Configuration.AddAzureKeyVault(validUri, new DefaultAzureCredential()); + } + + return builder; + } +} +``` + +After creating the extension method, it's possible to call it from the `Program.cs` class, like so: + +```csharp +using Microsoft.AspNetCore.Builder; +using My.Project; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Extensions; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +builder.ConfigureKeyVault(); + +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .Build(); + +WebApplication app = builder.Build(); + +await app.BootUmbracoAsync(); + +app.UseUmbraco() + .WithMiddleware(u => + { + u.UseBackOffice(); + u.UseWebsite(); + }) + .WithEndpoints(u => + { + u.UseBackOfficeEndpoints(); + u.UseWebsiteEndpoints(); + }); + +await app.RunAsync(); +``` + +### Authentication + +There are different ways to access the Azure Key Vault. It is important that the user you are logging in with has access to the Key Vault. You can assign roles using the Azure Portal. + +1. Navigate to your Key Vault. +2. Select Access Control. +3. Select Add -> Add role assignment. +4. Select the preferred role. +5. Search for the user. +6. Click review + assign + +## Use Key Vault references for Azure App Service + +Azure Web Apps offers the ability to directly reference Key Vault secrets as App Settings. The benefit of this is you can securely store your secrets in Key Vault without any code changes required in your application. + +### Create a System Assigned Managed Identity + +To begin we first need to create a **Managed Identity** for the Azure Web App. This enables us to grant granular permissions to an identity representing the Web App. + +Head over to your Azure Web App and find **Identity** under **Settings**: + +![image](https://user-images.githubusercontent.com/11179749/196052374-cebcfbc3-848f-4866-8e0f-70a57e776f60.png) + +Under **System assigned** change the Status from Off to **On**. + +![image](https://user-images.githubusercontent.com/11179749/196052406-2205c1bc-504a-41be-86bf-81b1cabbc17f.png) + +A GUID will then be generated called **Object (principal) ID**. Take note of this ID as we will need it further on. + +### Update your Key Vault Access Policy + +{% hint style="info" %} +Alternatively, you can use Role-Based Access Control on your Azure Key Vault. + +Learn more about the difference between the two approaches and how to migrate between them on the [Azure Documentation platform](https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-access-policy). +{% endhint %} + +It is assumed you already have a Key Vault set up with a few Umbraco secrets inside. In your Key Vault head to **Access Policies**. + +![image](https://user-images.githubusercontent.com/11179749/196052540-e1368016-ad7a-4b69-b05c-2875a4f11998.png) + +At the top select **+ Create**. We are now going to add the **System Managed Identity** for the Web App to Key Vault. + +![image](https://user-images.githubusercontent.com/11179749/196052612-e3b2041c-785f-46f5-b9b5-d8ad33b893ac.png) + +You will now be presented with different permissions to set for your Web App. You only need **Get** and **List** for **Secret Permissions** only. Click **Next** to continue: + +![image](https://user-images.githubusercontent.com/11179749/196052668-124d1496-4486-4098-9198-eff809876c80.png) + +Enter the GUID you took note of earlier, into the **Search Box**. You will see your Web App listed. + +![image](https://user-images.githubusercontent.com/11179749/196052706-15431bf4-80ea-4bb7-b40e-ebda45264fb7.png) + +Click your Web App to Select and click Next and then Create: + +![image](https://user-images.githubusercontent.com/11179749/196052849-970a97c5-e945-415a-9469-a67f485424ea.png) + +If you visit the **Access Policies** section again you should now see your web app in the list and its permissions: + +![image](https://user-images.githubusercontent.com/11179749/196052924-0d0559c0-a414-4bbd-ab91-94fc25dc720f.png) + +### Link our Key Vault Secret to an Azure Web App + +In your Azure Web App head to **Configuration** under **Settings**. + +![image](https://user-images.githubusercontent.com/11179749/196053006-3a95fc5f-1038-4228-9ae4-467050ea5759.png) + +Here we can add **App Settings** and **Connection Strings** to the environment. + +1. Let us start off with the **Umbraco Database Connection String**. + +Under Connection Strings, select **Advanced Edit**. + +![image](https://user-images.githubusercontent.com/11179749/196053130-8fb6c2b9-61c7-4c02-a419-8570174c6646.png) + +Once you click on "**Advanced Edit"** a new window will open up. There you will need to paste in the following JSON Object inside the square brackets. Ensure you update `{keyvault-name}`, `{secret-name}` and `{version-id}`. + +```json +{ + "name": "umbracoDbDSN", + "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", + "type": "Custom", + "slotSetting": false +} +``` + +{% hint style="info" %} +You can obtain the Secret Uri by visiting the specific version of your secret and copying the Url: +{% endhint %} + +![image](https://user-images.githubusercontent.com/11179749/196054001-cc215c04-d29c-435a-ae7b-6e8efb7f3faa.png) + +The ID is optional but recommended as it enables you to control which version of the secret is used at your discretion. Leave it out if you always want the Web App to pull the latest version of the secret. + +Wait a moment and refresh the screen. You should see a Green tick. If you do not have a Green tick you need to review your Access Policies in the previous step. + +![image](https://user-images.githubusercontent.com/11179749/196053419-f53feba2-b8ed-4b98-99f0-ee68f58ac8e4.png) + +2. We will perform the same approach for our **App Settings**. We will be updating the following App Settings for Azure Blob Storage. + +```json +"Umbraco": { + "Storage": { + "AzureBlob": { + "Media": { + "ConnectionString": "", + "ContainerName": "" + } + } + } +``` + +Due to the secrets being nested we need to use double underscore `__` to correctly reference the value on our Web App. + +On the Web App select **Advanced Edit** for Application Settings: + +
+ +When clicking on "Advanced Edit", a new window will open up. There you will need to paste in the following JSON Objects inside the square brackets. Ensure you update `{keyvault-name}`, `{secret-name}` and `{version-id}`. + +```json +{ + "name": "Umbraco__Storage__AzureBlob__Media__ConnectionString", + "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", + "slotSetting": false +}, +{ + "name": "Umbraco__Storage__AzureBlob__Media__ContainerName", + "value": "@Microsoft.KeyVault(SecretUri=https://{keyvault-name}.vault.azure.net/secrets/{secret-name}/{version-id}/)", + "slotSetting": false +} +``` + +The ID is optional but recommended as it enables you to control which version of the secret is used at your discretion. Leave it out if you always want the Web App to pull the latest version of the secret. + +Wait a moment and refresh the screen. You should see Green ticks for both values. If you do not have a Green tick you need to review your Access Policies in the previous step. + +
+ +### Local Development + +1. [Sign in to Visual Studio using the credentials that can access the Key Vault.](https://docs.microsoft.com/en-us/visualstudio/ide/signing-in-to-visual-studio) +2. [Use Azure CLI to store your preferred account into the credential cache.](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli) +3. [An example of extending and referencing secrets in `appsettings.json` in your local development environment.](https://gist.github.com/tgreensill/26659111871fdc54d0ac20cc21e602e1) + +### Staging/Production + +1. [Managed identities for Azure resources](https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-6.0#use-managed-identities-for-azure-resources) +2. [X.509 certificate for non-Azure-hosted apps](https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-6.0#use-application-id-and-x509-certificate-for-non-azure-hosted-apps) +3. [Use Key Vault references for App Service and Azure Functions](https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references) diff --git a/17/umbraco-cms/extending/language-files/README.md b/17/umbraco-cms/extending/language-files/README.md new file mode 100644 index 00000000000..3b164dec53c --- /dev/null +++ b/17/umbraco-cms/extending/language-files/README.md @@ -0,0 +1,59 @@ +--- +description: >- + This article overviews how an Umbraco CMS website uses and manages + localization with language files. +--- + +# Language Files & Localization + +## Language Files & Localization + +Language files are used to localise the Umbraco backoffice, so Users can use Umbraco in their native language. This is particularly important for content editors who do not speak English. + +With language files, you can also: + +* Override existing (core) localizations. +* Define localization for your own package. + +### [UI Localization](../../customizing/foundation/localization.md) + +Defines how to use the UI Umbraco Localization. This is the primary source of localization for the backoffice. + +### [.NET Localization](net-localization.md) + +Defines how to use the .NET Core Umbraco Localization. This is only relevant for localization that happens server-side - for example, for sending emails. + +{% hint style="info" %} +You can use localization files for Document and Media Types as well. You can find more information about this in the [Document Type Localization](../../fundamentals/data/defining-content/document-type-localization.md) article. +{% endhint %} + +## Supported Languages + +Current [languages](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Core/EmbeddedResources/Lang) with their ISO codes that are included in new Umbraco installations are: + +* `bs-BS` - Bosnian (Bosnia and Herzegovina) +* `cs-CZ` - Czech (Czech Republic) +* `cy-GB` - Welsh (United Kingdom) +* `da-DK` - Danish (Denmark) +* `de-DE` - German (Germany) +* `en` - **English (United Kingdom)** (fallback language) +* `en-US` - English (United States) +* `es-ES` - Spanish (Spain) +* `fr-FR` - French (France) +* `he-IL` - Hebrew (Israel) +* `hr-HR` - Croatian (Croatia) +* `it-IT` - Italian (Italy) +* `ja-JP` - Japanese (Japan) +* `ko-KR` - Korean (Korea) +* `nb-NO` - Norwegian Bokmål (Norway) +* `nl-NL` - Dutch (Netherlands) +* `pl-PL` - Polish (Poland) +* `pt` - Portuguese (Portugal) +* `pt-BR` - Portuguese (Brazil) +* `ro-RO` - Romanian (Romania) +* `ru-RU` - Russian (Russia) +* `sv-SE` - Swedish (Sweden) +* `tr-TR` - Turkish (Turkey) +* `ua-UA` - Ukrainian (Ukraine) +* `zh-CN` - Chinese (China) +* `zh-TW` - Chinese (Taiwan) diff --git a/17/umbraco-cms/extending/language-files/net-localization.md b/17/umbraco-cms/extending/language-files/net-localization.md new file mode 100644 index 00000000000..44344d57a67 --- /dev/null +++ b/17/umbraco-cms/extending/language-files/net-localization.md @@ -0,0 +1,116 @@ +--- +description: NET Umbraco Core Localization files. +--- + +# .NET Localization + +In this article, you will find information about the Core Localization files. You can also find information about where to find and use them, and how to keep them up-to-date. + +## Use cases + +.NET localization has limited use cases in Umbraco, as all backoffice localization is performed with [UI Localization](../../customizing/foundation/localization.md). + +In other words, .NET localization is only applied server-side with no accompanying UI - for example: + +* Sending emails. +* User login error handling. +* Health checks. + +## Where to find the core localization files + +The core Umbraco localization files are found at the following location within the [Umbraco source](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Core/EmbeddedResources/Lang): + +```xml +Umbraco-CMS/src/Umbraco.Core/EmbeddedResources/Lang/ +``` + +These localization files are shipped with Umbraco and should not be modified. + +### User localization files + +If you want to override Umbraco Core .NET localization, create new files in the following location and format: + +```xml +/config/lang/{language}.user.xml +``` + +{% hint style="info" %} +The `/config/lang/` folders do not exist on a clean installation of the CMS. You will need to create them at the root of your project. In an Umbraco Cloud project this will need to be in the `src` project. +{% endhint %} + +In order for these files to deploy when you do a `dotnet publish`, you need to add the following to your `.csproj` file: + +```xml + + + +``` + +## Using the localizations + +`ILocalizedTextService` is used to localize strings, and is available through dependency injection. You can use the `Localize()` method available in the namespace `Umbraco.Extensions` to localize the string by `area` and `key`: + +```csharp +using Umbraco.Cms.Core.Services; + +namespace UmbracoDocs.Samples; + +public class LocalizationSample +{ + private readonly ILocalizedTextService _localizedTextService; + + public LocalizationSample(ILocalizedTextService localizedTextService) + => _localizedTextService = localizedTextService; + + public string LocalizeMyText(string area, string key) + => _localizedTextService.Localize(area, key); +} +``` + +## Help keep the language files up to date + +As Umbraco is a continually evolving product it is inevitable that new text is added regularly to the English language version of these files. This may mean that some of the above languages are no longer up to date. + +If a translation is missing, the key "**alias**" used will be shown within the user interface, as an example: + +```xml +[assignDomain] +``` + +The language files are XML files with a straight-forward layout as seen below. + +```xml + + + + The Umbraco community + https://community.umbraco.com + + + Culture and Hostnames + Audit Trail + ... + + ... + +``` + +In the above example of a missing translation for "**assignDomain**", locate this string in the en.xml file. Then copy the whole "**Key**" element into the relevant language file. Afterwards you can translate the text, as an example here is the Spanish version of the above snippet: + +```xml + + + + The Umbraco community + https://community.umbraco.com + + + Administrar hostnames + Auditoría + ... + + ... + +``` + +If you modify core language files or introduce a new language, you can assist the community by sharing your updates. This can be done by [submitting a pull request](https://github.com/umbraco/Umbraco-CMS/blob/main/.github/CONTRIBUTING.md) so that your changes are merged into the core. diff --git a/17/umbraco-cms/extending/packages/README.md b/17/umbraco-cms/extending/packages/README.md new file mode 100644 index 00000000000..bb9c6ac7fff --- /dev/null +++ b/17/umbraco-cms/extending/packages/README.md @@ -0,0 +1,72 @@ +--- +description: "A package extends the functionality of Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco." +--- + +# Packages + +## What is a Package? + +A package extends Umbraco to provide additional functionality to editors, developers, site visitors, and all other types of users of Umbraco. It can impact one or more of these groups of people depending on the type of package. + +An Umbraco Package can be many things, but is generally characterized by: + +- Adding or extending functionality in the Umbraco CMS +- Empowering people to do more and/or do things more efficiently +- Engaging community members in collaboration and sharing +- Solving real life problems +- Inspiring people on what Umbraco can be made capable of + +### Categories of packages + +Packages provide a wide variety of functionality, and can often span multiple categories. In general, though, the functionality they provide fall into these main groups: + +- [Schema Extensions](#schema-extensions) +- [Management Extensions](#management-extensions) +- [Starter Kits](#starter-kits) +- [Integration Extensions](#integration-extensions) + +#### Schema Extensions + +A package that can be categorized as a Schema Extension will extend the default Umbraco Schema. Schema in this sense refers to things like Data Types, Property Editors, Document Types and Media Types. By extending Umbraco with packages such as [Our.Umbraco.GMaps](https://marketplace.umbraco.com/package/our.umbraco.gmaps) editors are given greater capabilities when they are populating their content pages. + +#### Management Extensions + +A Management Extension package helps you manage your site, and provides information to the users. Management extensions typically contain custom sections or dashboards to facilitate site management. [Diplo God Mode](https://marketplace.umbraco.com/package/diplo.godmode) is an example of a comprehensive management extension package with additional tools and information. + +#### Starter Kits + +Starter kits are, as the name suggests, a package that helps you set up a starter version of whatever you want to build. Most starter kit packages are for starting a website, and include schema like Document Types and Templates as well as content nodes and media. There are also some specialized starter kits, for example for creating a blog. Umbraco HQ has released their [own starter kit](https://www.nuget.org/packages/Umbraco.TheStarterKit), that creates a small site with the most commonly used features. + +#### Workspace Views + +Workspace Views are almost like dashboards for content nodes that are intended to display node specific information. A good example of this is the [Preflight](https://marketplace.umbraco.com/package/preflight.umbraco) content app. It shows you readability scores for your written content, directly on each content node. + +#### Integration extensions + +This type of package can be a lot of things, and can include a number of the other package types. They are generally integrating a larger system into Umbraco. A good example could be an e-commerce package such as [Umbraco Commerce](https://docs.umbraco.com/umbraco-commerce), that includes an entire webshop module for Umbraco. + +## [Creating a Package](creating-a-package.md) + +This short tutorial will teach you how to create a package in the Umbraco backoffice. It will also give a quick overview of what a generated package will contain. + +## [Language file for packages](language-files-for-packages.md) + +Package authors who would like their UI to be multi-lingual can include their own set of language files as part of their package distribution. + +## [Listing a Package on the Umbraco Marketplace](listing-on-marketplace.md) + +Once you've created a package make it available on the Umbraco Marketplace to share it with the community. + +## [Packages on Umbraco Cloud](packages-on-umbraco-cloud.md) + +Things you should know if you are developing for Umbraco Cloud. + +## [Maintaining Packages](maintaining-packages.md) + +Some guidance on how to maintain your package after release. + +## [An Example Package Repository](example-package-repository.md) + +There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment. + +If you are looking for inspiration to follow form some tried and tested packages, read more here. diff --git a/17/umbraco-cms/extending/packages/accessibility.md b/17/umbraco-cms/extending/packages/accessibility.md new file mode 100644 index 00000000000..733e096667f --- /dev/null +++ b/17/umbraco-cms/extending/packages/accessibility.md @@ -0,0 +1,22 @@ +# Create accessible Umbraco packages + +Creating accessible packages extends on accessibility in an [Umbraco context](https://www.skrift.io/issues/accessibility-in-an-umbraco-context/). + +The Umbraco UI components have been built to be accessible and have accessibility tests built within them. Building the user interface (UI) using these [Umbraco UI components](https://uui.umbraco.com/) ensures that the package is as accessible as the Umbraco backoffice. + +In addition, any fixes and updates to the UI components will be pushed through to the packages when you rebuild them with the updates. + +## Testing + +Accessibility testing is more a specialist skillset than it is automated testing. The purpose of this document is to outline what can be done to help build accessible packages. It is not a complete list of accessibility tests that can be performed. + +- Build the components using the [Umbraco UI components](https://uui.umbraco.com/) as these have accessibility tests built within them. +- Use the keyboard to tab through the elements on the page checking: + - Does the element tabbed to have a **focus state**? + - Does the **tab order** make sense? + - More on focus, tab orders, other common interactions and techniques for keyboard testing can be found at [WebAIM: Keyboard Accessibility](https://webaim.org/techniques/keyboard/) +- Check the UI with a screen reader. + - [Non Visual Desktop Access (NVDA) is a free Windows screen reader](https://www.nvaccess.org/download/) and some guidelines on screen reader testing are available from [WebAIM: Web Accessibility In Mind](https://webaim.org/articles/screenreader_testing/) +- Install an accessibility testing tool as a plugin into your browser to run automated tests: + - Tools like [axe DevTools](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd) are built to reduce the number of false positives in a test. +- If the UI does not follow the Umbraco Style, then check the contrast with a tool like the [Web Content Accessibility Guidelines (WCAG) Contrast Checker](https://chrome.google.com/webstore/detail/wcag-color-contrast-check/plnahcmalebffmaghcpcmpaciebdhgdf). This will help ensure contrast. diff --git a/17/umbraco-cms/extending/packages/creating-a-package.md b/17/umbraco-cms/extending/packages/creating-a-package.md new file mode 100644 index 00000000000..6f3e5a0d1ee --- /dev/null +++ b/17/umbraco-cms/extending/packages/creating-a-package.md @@ -0,0 +1,384 @@ +--- +description: Tutorial to create a package in Umbraco +--- + +# Creating a Package + +This tutorial demonstrates how to create a package in Umbraco. The process described is based on creating a package from the dashboard in the [Creating a Custom Dashboard Tutorial](../../tutorials/creating-a-custom-dashboard/). The same approach can be applied to other packages as well. + +## Creating a Package Schema in the Backoffice + +To begin creating a package, start by setting up a package schema in the Umbraco backoffice: + +1. Navigate to the `Packages` section. +2. Select `Created` in the top-right corner of the screen. +3. Click the `Create package` button. + +![Creating a package schema in the Backoffice](images/create-package.png) + +On the `Create package` page, there are different fields that allow you to define the contents of the package based on backoffice items. + +4. Enter the Package Name at the top. For this tutorial, name the package `Custom Welcome Dashboard` matching the name used in the [Creating a Custom Dashboard Tutorial](../../tutorials/creating-a-custom-dashboard/). +5. Fill in the required fields. For more information, see the [Package Content Section](#package-content-section). +6. Click `Create` to generate the package schema. +7. Click `Download` to download the package and inspect its contents. + +### Package Content section + +These fields determine which backoffice items will be included in the package. For this example, the following settings are used: + +| Property | Value | Note | +| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Content | _Empty_ | Here, you can include content. For example, if you want to create a starter kit. Not relevant for this package though. | +| Media | _Empty_ | Here, you can include media. For example, if you want to add media to the starter kit. Not relevant for this package though. | +| Document Types | _Empty_ | Similar to the Content picker above. If you include content, you will also need to pick all its dependencies in this and the next steps for them to be packaged together. | +| Media Types | _Empty_ | Similar to the Media picker above. If you include media, you will also need to pick all its dependencies in this and the next steps for them to be packaged together. | +| Languages | _Empty_ | See `Document Types` above. All text is hardcoded or within the lang folder in this package, so this is not needed. | +| Dictionary | _Empty_ | See `Document Types` above | +| Data Types | _Empty_ | See `Document Types` above | +| Templates | _Empty_ | See `Document Types` above | +| Stylesheets | _Empty_ | These will come from the **wwwroot/css** folder. If you have stylesheets you want to include from other locations (_like App_Plugins folder_) you can do so at a later step. | +| Scripts | _Empty_ | These will come from the **wwwroot/scripts** folder. If you have scripts you want to include from other locations (_like App_Plugins folder_) you can do so at a later step. | +| Partial Views | _Empty_ | See `Document Types` above | + +## Inspecting the Package ZIP + +If the package includes backoffice-specific items, the downloaded ZIP will contain the `package.xml` along with a folder for any media items included. The contents of the ZIP package might look like this: + +![Contents of the ZIP package](images/zip-package-contents.png) + +The `package.xml` file contains the metadata for the package, while additional files (if any) are referenced within the XML. + +Below is an example of the `package.xml` file: + +```xml + + + + + Custom Welcome Dashboard + + + + + + + + + + + + + +``` + +This XML file contains package metadata, and references where Umbraco should place the files upon installation. + +Since this example package does not include backoffice items, only the package name appears, with other tags left empty. + +## Creating a NuGet package + +NuGet packages are the preferred method for distributing Umbraco extensions. NuGet enables better practices for source control and deployment. This section outlines how to create a NuGet package for the custom dashboard that extends Umbraco’s functionality. + +NuGet is the standard package manager for .NET. More details on NuGet can be found in the [Microsoft Documentation](https://docs.microsoft.com/en-us/nuget/what-is-nuget). + +### Generate an Empty Package Using a Template + +1. Install the latest [.NET SDK](https://dotnet.microsoft.com/download). +2. Run `dotnet new install Umbraco.Templates` to install the project templates. +3. Run `dotnet new umbraco-extension -n CustomWelcomeDashboard` to create a new package project. + +{% hint style="info" %} +If the post-installation script fails due to PowerShell restrictions, manually run `npm install` and `npm run build` in the `Client` folder. +{% endhint %} + +This command will generate the following files: + +![Content of an empty package](images/empty-package-from-template-v15.png) + +Apart from the project file, the generated structure includes key folders and files that are essential for building an Umbraco extension. + +- **Client** - where you can place any front-end assets, such as JavaScript, CSS, and Angular views, that will be used in the backoffice. +- **Composers** - intended for C# composer classes, which are used to register dependencies and configure services in Umbraco. +- **Controllers** - where you can add API controllers if your package requires custom endpoints. +- **Constants.cs** - serves as a placeholder for any global constants your package may need. + +Unlike previous versions, the `umbraco-extension` template does not generate a `package.manifest` file or an `App_Plugins` folder by default. If your package includes client-side assets for the backoffice, you will need to manually create an `App_Plugins/{YourPackageName}` folder. + +Additionally, the `.csproj` file is configured to support NuGet packaging, allowing you to distribute your extension. If you plan to include custom C# logic, the files you place in the root folder will be compiled into the package DLL. + +### Transfer Files + +Since the `umbraco-extension` template does not generate an `App_Plugins` folder by default, you will need to manually create it. + +1. Create an `App_Plugins` folder in the downloaded package folder. +2. Go to the `welcome-dashboard` folder created in the [Creating a Custom Dashboard Tutorial](../../tutorials/creating-a-custom-dashboard/README.md#setting-up-a-package). +3. Transfer or copy the `welcome-dashboard` folder in the `App_Plugins` folder. + +![App_Plugins with dashboard files](images/app-plugins-content.png) + +### Specify Package Properties + +You can specify package metadata directly in the `csproj` file. Here, is an example of some package properties: + +```xml + + + . . . + CustomWelcomeDashboard + Custom welcome dashboard for Umbraco. + umbraco plugin package + 1.0.0 + Your Name + https://umbraco.com + MIT + + . . . + +``` + +Alternatively, right-click the `csproj` file in Visual Studio > **Properties** > **Package** and add the required information: + +![Adding Package properties in Visual Studio](images/Package-properties-Visual-Studio.png) + +The properties that can be specified include: + +| Property | Value | Note | +| ------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Version | 1.0.0 | This is automatically set to 1.0.0 but can be changed as appropriate. | +| Authors | Your name | Here you get to take credit for your awesome work! | +| PackageProjectUrl | https://umbraco.com | This URL will be shown as the package's URL when others install it. It will likely be a GitHub repository, or similar. | +| PackageLicenseExpression | MIT | The license is set to MIT. Please consider how you want your package licensed. If in doubt when deciding an open-source license there are [good resources available](https://choosealicense.com/licenses/). | + +### Pack the Package + +To create the actual NuGet package, use the `dotnet pack` command. You can either output the package to the default `bin` folder or specify a custom location. + +#### Default Output + +Run the command in the package directory to generate the package in the `bin` folder: + +```sh +dotnet pack +``` + +![Package output in `bin` folder](images/package-default-location.png) + +#### Custom Output Location + +To specify a different output location, use the following command: + +```sh +dotnet pack --output MyNugetPackages +``` + +![Package output in `MyNugetPackages` folder](images/package-custom-folder.png) + +It will pack the project in the current directory and place the resulting package into the `MyNugetPackages` folder. + +### Publish the Package + +To share the package with others, publish it to a public NuGet repository, such as [https://nuget.org](https://nuget.org). + +The official [NuGet Documentation](https://docs.microsoft.com/en-us/nuget/nuget-org/publish-a-package) provides a detailed guide on how to publish a package to NuGet.org. + +To release packages to only a limited audience, see the [Hosting your own NuGet feeds](https://docs.microsoft.com/en-us/nuget/hosting-packages/overview) documentation. + +For Umbraco-specific packages, refer to the [Listing Your Package](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package) guide to feature your package on the Umbraco Marketplace. + +## Installing a NuGet Package + +To install the NuGet package, you can use Visual Studio, Rider, or the CLI. + +In the CLI, create a new Umbraco project and add the package reference: + +```cs +dotnet new umbraco -n CustomWelcomeDashboardProject +cd CustomWelcomeDashboardProject +dotnet add package CustomWelcomeDashboard.1.0.0 +dotnet run +``` + +You can check that the NuGet package was referenced in your solution and that the **App_Plugins** assets were restored successfully. The custom dashboard should now be available in the Umbraco backoffice. + +For testing the package locally without publishing, use the `-p` flag to create a project that depends on the package. So when you build the new project, it will copy the **App_Plugins** folder from the package project into the test project. + +```cs +dotnet new umbraco -n CustomWelcomeDashboardProject -p CustomWelcomeDashboard +``` + +Go to the `CustomWelcomeDashboardProject` directory, build your Umbraco website using the `dotnet build` command, and then run the application. + +### Package Migration + +Umbraco supports automatic and custom package migrations to handle content updates when a package is installed. + +#### Automatic Package Migration + +For schema and content packages, inherit from the `AutomaticPackageMigrationPlan` and specify the package name that is displayed under the packages _Installed_ tab in the backoffice. You will also need to embed the schema file in the same namespace. + +```csharp +using Umbraco.Cms.Infrastructure.Packaging; + +namespace CustomWelcomeDashboardProject.Migrations; + +public class PackageMigrationPlan : AutomaticPackageMigrationPlan +{ + public PackageMigrationPlan() : base("Custom Welcome Dashboard") + { + } +} +``` + +![Automatic package migration](../../../../10/umbraco-cms/extending/packages/images/embeded-resource.png) + +{% hint style="info" %} +Whenever the embedded package.xml file changes, the automatic package migration plan is executed again. This is due to the fact that the migration state is based on the file hash. Existing schema or content will not be overwritten in this process. +{% endhint %} + +#### Custom Package Migration + +Instead of creating an automatic package migration plan, we will inherit from the `PackageMigrationPlan` and again specify the name of the package in the base constructor. Further on, we will define the plan using a unique GUID - in the example below we have a single migration called `MyCustomMigration`. + +```csharp +using Umbraco.Cms.Core.Packaging; + +namespace CustomWelcomeDashboardProject.Migrations; + +public class CustomPackageMigrationPlan : PackageMigrationPlan +{ + public CustomPackageMigrationPlan() : base("Custom Welcome Dashboard") + { + } + + protected override void DefinePlan() + { + To(new Guid("4FD681BE-E27E-4688-922B-29EDCDCB8A49")); + } +} +``` + +The custom migrations can inherit from `PackageMigrationBase` where we can use helper methods to pick up the schema. But we can also use the regular `MigrationBase` class. + +```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Packaging; + +namespace CustomWelcomeDashboardProject.Migrations; + +public class CustomPackageMigration : PackageMigrationBase +{ + public CustomPackageMigration( + IPackagingService packagingService, + IMediaService mediaService, + MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, + IShortStringHelper shortStringHelper, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + IMigrationContext context, + IOptions packageMigrationsSettings) + : base( + packagingService, + mediaService, + mediaFileManager, + mediaUrlGenerators, + shortStringHelper, + contentTypeBaseServiceProvider, + context, + packageMigrationsSettings) + { + } + + protected override void Migrate() + { + ImportPackage.FromEmbeddedResource().Do(); + } +} +``` + +If your migration step has a requirement for asynchronous work, you can also inherit from `AsyncPackageMigrationBase`: + +```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Infrastructure.Migrations; +using Umbraco.Cms.Infrastructure.Packaging; + +namespace Umbraco.Cms.Web.UI.Custom.PackageMigration; + +public class CustomPackageAsyncMigration : AsyncPackageMigrationBase +{ + + public TestMigrationStep2( + IPackagingService packagingService, + IMediaService mediaService, + MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, + IShortStringHelper shortStringHelper, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + IMigrationContext context, + IOptions packageMigrationsSettings, + IUserGroupService userGroupService, + IUserService userService) + : base( + packagingService, + mediaService, + mediaFileManager, + mediaUrlGenerators, + shortStringHelper, + contentTypeBaseServiceProvider, + context, + packageMigrationsSettings) + { + } + + protected override async Task MigrateAsync() + { + // Use await for asynchronous work. + } +} +``` + +Here we also added the ZIP file as an embedded resource to the package project. + +![ZIP as an embedded resource](<../../../../10/umbraco-cms/extending/packages/images/embeded-resource-props (1).png>) + +![Automatic package migration](<../../../../10/umbraco-cms/extending/packages/images/embeded-zip-resource (1).png>) + +Whichever migration plan you choose to create, you will be able to see that your package has been installed after the migration is completed. + +![Installed package](../../../../10/umbraco-cms/extending/packages/images/installed-package.png) + +When using a custom package migration plan, the current state is ignored by default. This causes it to execute all migrations again whenever this isn't the same as the final state of the plan (e.g. if you added a new migration). This is due to the `IgnoreCurrentState` being set to `true` in the `PackageMigrationPlan` base class. You can override this property and set it to `false` again to make it behave like regular migration plans and only run the migrations that have not yet been executed on the current environment. + +### Attended/Unattended migration execution + +After creating a migration plan, the content and schema will automatically be imported either during unattended package migration or from the Packages section in the backoffice. + +By default, all these package migrations are executed unattended during startup but the solution owners can disable this in the configuration. IntelliSense can help, as well as provide further information about the `PackageMigrationsUnattended` setting. Then in the Packages section, there will be an option to run the package migration for each package individually when the `PackageMigrationsUnattended` is set to `false`. + +```json + "Umbraco": { + "CMS": { + . . . + "Unattended": { + "PackageMigrationsUnattended": false + } + } + } +``` + +![Attended package install](../../../../10/umbraco-cms/extending/packages/images/package-install-attended.png) + +The configuration of package migrations can be different for each environment and makes it possible to have the migration executed unattended on the development environment, but leave them out or manually execute them on other environments. This is useful when you use a tool like Umbraco Deploy or USync as these will migrate the content. diff --git a/17/umbraco-cms/extending/packages/example-package-repository.md b/17/umbraco-cms/extending/packages/example-package-repository.md new file mode 100644 index 00000000000..2d861a71710 --- /dev/null +++ b/17/umbraco-cms/extending/packages/example-package-repository.md @@ -0,0 +1,83 @@ +--- +meta.Title: An Example Package Repository +description: >- + Suggestions for organizing and Umbraco package source code repository. +--- + +# An Example Package Repository + +There are many ways to build and deploy your package to NuGet. You will likely have your own approach for organizing a solution and preferred tools for build and deployment. + +It may be useful though to review some practices we share here, of how we build packages at Umbraco. + +Some add-ons to the CMS created by Umbraco are closed-source, but we have some we make freely available with open-source repositories. An example is [Umbraco.AuthorizedServices](../../../../marketplace-and-integrations/packages/authorized-services.md), that has a source code repository [here on GitHub](https://github.com/umbraco/Umbraco.AuthorizedServices). + +## Solution Organization + +The solution consists of three projects. + +### Package Project + +The [main package project](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/src/Umbraco.AuthorizedServices) lives in `src/`. It contains in the project file a dependency on Umbraco CMS: + +```xml + +``` + +Here we provide an upper bound on the package. This ensures that developers can only install it into projects that are using versions of Umbraco that we have tested the package with. + +When the next major version of Umbraco is released, we'll test and either extend the range or release a new version, as appropriate. + +### Tests Project + +We have a [project for unit tests](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/tests/Umbraco.AuthorizedServices.Tests) in `tests/.Tests`. It contains references to `Umbraco.Cms.Tets` and a project reference to the package: + +```xml + +``` + +### Example Website + +Finally there's an [example Umbraco website](https://github.com/umbraco/Umbraco.AuthorizedServices/tree/main/examples/Umbraco.AuthorizedServices.TestSite) that we use for manual testing of the package. It also has a project reference to the package project, allowing us to test updates as they are compiled. + +### Solution Items + +As well as the projects, the following files are added to the solution: + +- [.artifactignore](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.artifactignore) - used by Azure DevOps services to [control which files are uploaded when you publish](https://learn.microsoft.com/en-us/azure/devops/artifacts/reference/artifactignore?view=azure-devops). This helps to reduce pipeline execution time. +- [.editorconfig](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.editorconfig) - used to [enforce consistent coding styles](https://editorconfig.org/) for multiple developers working on the same project across editors and IDEs. +- [.gitignore](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.gitignore) - controls which files are added to source control. +- [.globalconfig](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/.globalconfig) - provides [further styling rules for the project files, even if stored outside of the project directory](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/configuration-files#global-analyzerconfig). +- [Directory.Build.props](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/Directory.Build.props) - used to provide common setting across all projects in the solution. +- global.json - ensures that the solution is always [built with a consistent version of .NET](https://learn.microsoft.com/en-us/dotnet/core/tools/global-json). We add this when we have a solution that targets a single Umbraco major version. +- [LICENSE.md](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/LICENSE.md) - indicates the license through which the code is available. +- [README.md](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/README.md) - a top-level documentation page for the source code repository. +- [icon.png](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/icon.png) - an icon used for the package on NuGet and the Umbraco Marketplace. +- [umbraco-marketplace.json](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/umbraco-marketplace.json) - provides [additional details about the package when listed on the Umbraco Marketplace](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package). +- [version.json](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/version.json) - provides package versioning information for use by [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning). We use this tool for generating version numbers. + +## Build and Deployment + +We use Azure DevOps pipelines for continuous integration and releasing new versions of the package. The definition of how the project is built is defined in a `.yaml` file that's part of the source code repository. + +The file can be found [here](https://github.com/umbraco/Umbraco.AuthorizedServices/blob/main/azure-pipeline%20-%20Umbraco.AuthorizedServices.yml). + +Even if using another tool it may be worth reviewing how we have setup our pipeline. It may be you can setup something similar with your own provider. + +### Building the Package + +The build consists of two stages: building the solution and running unit tests. Only if both succeed is the build as a whole considered successful. + +![Azure DevOps build pipeline](../../../../10/umbraco-cms/extending/packages/images/azuredevops-build.png) + +### Releasing the Package + +We release the package manually in Azure DevOps, with a two stage process. Firstly we release to a "pre-releases" feed, and then after manual approval, to NuGet. + +![Azure DevOps release pipeline](../../../../10/umbraco-cms/extending/packages/images/azuredevops-release.png) + + + + + + diff --git a/17/umbraco-cms/extending/packages/good-practice-and-defaults.md b/17/umbraco-cms/extending/packages/good-practice-and-defaults.md new file mode 100644 index 00000000000..9c34c2f7a83 --- /dev/null +++ b/17/umbraco-cms/extending/packages/good-practice-and-defaults.md @@ -0,0 +1,208 @@ +--- +description: >- + Information on good practices and common defaults for Umbraco package + development. +--- + +# Good practice and defaults + +This document provides guides and notes on package development. It includes good practice guidelines that will help you maintain and support your package through multiple releases and versions of Umbraco. These good practices are not prescriptive, but offer a guide as to what often works well, and not-so-well, when developing packages for Umbraco. + +## Backoffice assets (JS/CSS/HTML) + +To extend the Umbraco backoffice, a package can provide files such as `umbraco-package.json` and TypeScript/JavaScript files that should be stored within the `App_Plugins` folder. It's recommended to put all files in a subfolder with a unique name, preferably using the package name, like `App_Plugins\MyPackage`. + +For more information on how to extend the Umbraco backoffice, have a look at the [customizing the backoffice documentation](../../customizing/overview.md) + +Files in the `App_Plugins` folder will be publicly available on the website even though they are not in the `wwwroot` folder. You should not store sensitive information in the `App_Plugins` folder. + +Files in the `App_Plugins` folder should be considered immutable. This means that they are not something a user of your package is expected to change on their site. + +The default delivery method for files to the `App_Plugins` folder is via a `.targets` file within a package. This means when a website is built, the files in this folder are copied over from the NuGet cache. When this happens, any changes a user might have made to these files will be lost. Equally, if the user performs a `dotnet clean` on a solution, all files in the `App_Plugins` folder will be deleted. + +{% hint style="info" %} +If you have files that you expect users of your package to alter you should not place them in the `App_Plugins` folder. +{% endhint %} + +## Views + +Views are used to render content on the front end of a website. If your package provides a way for the user to present the content publicly, you should copy these files to the views folder. + +As the files will still be copied during build you should ensure your target file does not overwrite newer or altered files. You should also ensure that it doesn't delete files on clean. + +{% hint style="info" %} +When you have a package that contains many views you might consider building a dotnet template or Razor Class Library (RCL) instead. By doing this, the files will not pollute your user's solutions. +{% endhint %} + +## License files + +Umbraco products store their licenses in `/umbraco/Licenses`. It is recommended for third-party packages that require license files to also store their license files in this location. + +The default `.gitignore` for Umbraco templates will include any files in the `/Licenses` folder while ignoring most of the rest of the Umbraco folder. + +{% hint style="info" %} +The `/umbraco/Licenses` folder does not exist on a fresh installation of Umbraco. You need to create it manually before you save your license file to this folder. +{% endhint %} + +## Operating system considerations + +Umbraco a .NET application and can be run on multiple operating systems (Windows, Linux and macOS). When developing packages there are a few things you should be aware of for your package to run on all possible operating systems. + +### Case sensitivity + +The Linux and macOS file systems are case-sensitive by default. This means that `App_Plugins/myPackage` is a different location from `app_plugins/MyPACKAGE`. When building your package you should ensure that you always refer to folders and paths in a consistent way. + +A good way to ensure consistency is to use constants in your code to define file or folder locations. + +{% hint style="info" %} +You can adjust the case sensitivity of a Windows folder by running a command against a newly created/empty folder: + +```bash +fsutil.exe file queryCaseSensitiveInfo +``` +{% endhint %} + +#### Case sensitivity in default files and folders + +Some folders within Umbraco will already exist for all installations. If you access these folders, you need to be aware of the case used to ensure you end up in the correct place: + +| Folder | Note | +| ---------------------- | ------------------------------------------------------------------------------------- | +| /App\_Plugins | Uppercase `A` and `P` | +| /App\_Plugins/\[Ll]ang | Uppercase `L` | +| /Views | Uppercase `V` | +| /umbraco/Licenses | Lowercase `u` and uppercase `L` | +| /config | Lowercase `c` | + +{% hint style="info" %} +If you create a custom section/tree, Umbraco will build paths based on the name of that section or tree. These folder paths will be case-sensitive. + +For example: if you have a custom tree with the `treeAlias` of `MyCustomTree` Umbraco will look for files in `App_Plugins\MyPackage\backoffice\MyCustomTree\`. +{% endhint %} + +### File/folder locations + +You should never hardwire a file or folder location into code. Instead, it is recommended to follow either of the options below: + +* Access files using the ASP.NET Core file providers from `IHostingEnvironment`. +* Use the built-in methods to access well-known locations (see below). + +#### Temp folder + +The location of the Umbraco temp folder can be controlled via configuration and cannot be assumed. Use the `IHostingEnvironment.LocalTempPath` variable to locate the temp folder. + +```csharp +var localTempRoot = Path.GetFullPath(hostingEnvironment.LocalTempPath); +``` + +#### Relative paths + +If you require the path of a folder relative to the site root, you can use the `IHostingEnvironment` method to map a path: + +```csharp +// Full physical path to the content/project root +var contentRootPath = hostingEnvironment.MapPathContentRoot("~/"); +// Full physical path to the web root (served publicly) +var webRootPath = hostEnvironment.MapPathWebRoot("~/"); +// Absolute path to use as URL +var absolutePath = hostEnvironment.ToAbsolute("~/"); +``` + +### Folder/file system access + +It is not recommended to assume things about the folder structure of a site or use direct I/O commands to access the file system. Access to the disk within an ASP.NET Core site is usually managed with File Providers. You can access the file providers from the `IWebHostEnvironment` class. + +Example: If you want to read `robots.txt` from the `wwwroot` folder, use `WebRootFileProvider` in a controller to get to the root of the site and read the file: + +```csharp +public class MyController: UmbracoAuthorizedJsonController +{ + public MyController(IWebHostEnvironment webHostEnvironment) + { + var webRootProvider = webHostEnvironment.WebRootFileProvider; + + var myFileInfo = webRootProvider.GetFileInfo("robots.txt"); + if (myFileInfo.Exists) + { + using (var stream = myFileInfo.CreateReadStream()) + { + using(var streamReader = new StreamReader(stream)) + { + var text = streamReader.ReadToEnd(); + } + } + } + } +} +``` + +{% hint style="info" %} +This is the preferred method for file I/O. Not all files served up by a site are placed in the `wwwroot` folder when you expect them to be. This is especially true if the site is using Razor Class Library projects to insert static files. +{% endhint %} + +### Path manipulation + +Building folder path strings manually can cause problems when swapping between file systems. Windows uses the backslash character ('\\') to separate folders and files while Linux uses the forward slash ('/'). + +#### Example + +On Windows, a file might be located at `d:\website\robots.txt` while on Linux this might look like `/home/website/robots.txt` instead. + +You should use the .NET `Path` methods wherever possible when building paths to ensure that the correct path is built: + +```csharp +// WRONG: Don't build paths manually +var myPath = webrootPath + "\robots.txt"; + +// CORRECT: Build the path using the correct separator for the current file system +var myPath = Path.Combine(webrootPath, "robots.txt"); +``` + +If you need to build a path manually, use `Path.DirectorySeparatorChar` instead to get the correct separator for the file system. + +## Settings + +Most packages will require some settings to be stored for the users to control in order to change the behavior of the package. Where you store these settings will depend a lot on the nature of the package. + +### Property Editors + +Property Editors should store their settings as part of their Data Type in Umbraco. This is the standard way property editor behavior is controlled while it is familiar to users and supported by deployment tools. + +### Do not save to appsettings.json + +You should not alter `appsettings.json` via code. + +Settings in ASP.NET Core are merged from a number of different locations at runtime. You cannot guarantee that `appsettings.json` is the location that a setting is read from and your users may not want certain settings in that file. You can read settings from the configuration, but you cannot assume they have come from `appsettings.json`. + +### Settings locations + +There are many options for where you might save your settings and a lot will depend on the nature of your package. + +Below you can find pros and cons for different places where you might save the settings for your package. + +#### Save to the database + +Settings can be saved to the database. Settings can be stored in the database using the Umbraco `IKeyValueService`, and for more complex settings you can use a custom database table. + +* Pros: + * Settings will be accessible directly from the database, and not dependent on deployed files on disk. +* Cons: + * Setup is required to create the database tables for the settings to live in. + * The settings will only be available to the specific instance of the site, and any settings will not be deployed between a local, development, or staging site. + +#### Save to disk + +You can choose to save the settings to disk. As an example, the settings can be saved in the `/config` folder at the root of the site. + +* Pros: + * Settings will be accessible to the site and can be included in deployments between sites. +* Cons: + * You cannot guarantee that the folder or files will be present on a site or that they will be writable. + * Using your own config means your users cannot harness the power of the .NET Core configuration system and move settings to environment variables or other key/value stores. This means that sensitive information may end up on disk. + +#### Provide the users with appsettings.json snippets + +You could choose to provide your users with a snippet they can copy into their `appsettings.json` file. This will ensure that the settings are stored in the correct location. + +* Pro: Allows your users to fully control how and where the settings are stored (eg. secure key/value stores). +* Con: Requires the user to edit files on disk to get the settings in place. diff --git a/17/umbraco-cms/extending/packages/images/Package-properties-Visual-Studio.png b/17/umbraco-cms/extending/packages/images/Package-properties-Visual-Studio.png new file mode 100644 index 00000000000..8312d1e8cf7 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/Package-properties-Visual-Studio.png differ diff --git a/17/umbraco-cms/extending/packages/images/PackagesPage.png b/17/umbraco-cms/extending/packages/images/PackagesPage.png new file mode 100644 index 00000000000..cff25527501 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/PackagesPage.png differ diff --git a/17/umbraco-cms/extending/packages/images/app-pligins-contents.png b/17/umbraco-cms/extending/packages/images/app-pligins-contents.png new file mode 100644 index 00000000000..c0350372ad7 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/app-pligins-contents.png differ diff --git a/17/umbraco-cms/extending/packages/images/app-plugins-content.png b/17/umbraco-cms/extending/packages/images/app-plugins-content.png new file mode 100644 index 00000000000..69803716887 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/app-plugins-content.png differ diff --git a/17/umbraco-cms/extending/packages/images/app-plugins-starterkit.png b/17/umbraco-cms/extending/packages/images/app-plugins-starterkit.png new file mode 100644 index 00000000000..f69d24e28df Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/app-plugins-starterkit.png differ diff --git a/17/umbraco-cms/extending/packages/images/backoffice-installed-packages.png b/17/umbraco-cms/extending/packages/images/backoffice-installed-packages.png new file mode 100644 index 00000000000..74651ae2ada Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/backoffice-installed-packages.png differ diff --git a/17/umbraco-cms/extending/packages/images/backoffice-package-section.png b/17/umbraco-cms/extending/packages/images/backoffice-package-section.png new file mode 100644 index 00000000000..dca87d21e51 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/backoffice-package-section.png differ diff --git a/17/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png b/17/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png new file mode 100644 index 00000000000..c31ad803478 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/backoffice-packages-section-package.png differ diff --git a/17/umbraco-cms/extending/packages/images/backoffice-packages-section.png b/17/umbraco-cms/extending/packages/images/backoffice-packages-section.png new file mode 100644 index 00000000000..f14549ef229 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/backoffice-packages-section.png differ diff --git a/17/umbraco-cms/extending/packages/images/cloud-flow.png b/17/umbraco-cms/extending/packages/images/cloud-flow.png new file mode 100644 index 00000000000..1880ca8d129 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/cloud-flow.png differ diff --git a/17/umbraco-cms/extending/packages/images/create-package.png b/17/umbraco-cms/extending/packages/images/create-package.png new file mode 100644 index 00000000000..ec89f4f933f Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/create-package.png differ diff --git a/17/umbraco-cms/extending/packages/images/creating-package-menu-v9.png b/17/umbraco-cms/extending/packages/images/creating-package-menu-v9.png new file mode 100644 index 00000000000..da73453c0a6 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/creating-package-menu-v9.png differ diff --git a/17/umbraco-cms/extending/packages/images/creating-package-menu.png b/17/umbraco-cms/extending/packages/images/creating-package-menu.png new file mode 100644 index 00000000000..2bbadf1c1ba Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/creating-package-menu.png differ diff --git a/17/umbraco-cms/extending/packages/images/display-retired.png b/17/umbraco-cms/extending/packages/images/display-retired.png new file mode 100644 index 00000000000..9584bcae232 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/display-retired.png differ diff --git a/17/umbraco-cms/extending/packages/images/download-package-button.png b/17/umbraco-cms/extending/packages/images/download-package-button.png new file mode 100644 index 00000000000..ed8d1705221 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/download-package-button.png differ diff --git a/17/umbraco-cms/extending/packages/images/embeded-resource-props.png b/17/umbraco-cms/extending/packages/images/embeded-resource-props.png new file mode 100644 index 00000000000..ee8e0b6a49e Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/embeded-resource-props.png differ diff --git a/17/umbraco-cms/extending/packages/images/embeded-resource.png b/17/umbraco-cms/extending/packages/images/embeded-resource.png new file mode 100644 index 00000000000..f3ac2e59a1a Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/embeded-resource.png differ diff --git a/17/umbraco-cms/extending/packages/images/embeded-zip-resource.png b/17/umbraco-cms/extending/packages/images/embeded-zip-resource.png new file mode 100644 index 00000000000..4b85628f1a0 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/embeded-zip-resource.png differ diff --git a/17/umbraco-cms/extending/packages/images/empty-package-from-template-v15.png b/17/umbraco-cms/extending/packages/images/empty-package-from-template-v15.png new file mode 100644 index 00000000000..80e276ce065 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/empty-package-from-template-v15.png differ diff --git a/17/umbraco-cms/extending/packages/images/empty-package-from-template.png b/17/umbraco-cms/extending/packages/images/empty-package-from-template.png new file mode 100644 index 00000000000..0a692a5c54e Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/empty-package-from-template.png differ diff --git a/17/umbraco-cms/extending/packages/images/flag-as-retired.png b/17/umbraco-cms/extending/packages/images/flag-as-retired.png new file mode 100644 index 00000000000..bf4104ef5d4 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/flag-as-retired.png differ diff --git a/17/umbraco-cms/extending/packages/images/forum-create.png b/17/umbraco-cms/extending/packages/images/forum-create.png new file mode 100644 index 00000000000..7df1e4bd4ca Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/forum-create.png differ diff --git a/17/umbraco-cms/extending/packages/images/forums-display.png b/17/umbraco-cms/extending/packages/images/forums-display.png new file mode 100644 index 00000000000..accb6880390 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/forums-display.png differ diff --git a/17/umbraco-cms/extending/packages/images/forums-link.png b/17/umbraco-cms/extending/packages/images/forums-link.png new file mode 100644 index 00000000000..3c7540216a6 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/forums-link.png differ diff --git a/17/umbraco-cms/extending/packages/images/fromArtifact.png b/17/umbraco-cms/extending/packages/images/fromArtifact.png new file mode 100644 index 00000000000..22d50e7f5f1 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/fromArtifact.png differ diff --git a/17/umbraco-cms/extending/packages/images/generate-package=schema.png b/17/umbraco-cms/extending/packages/images/generate-package=schema.png new file mode 100644 index 00000000000..5df310e995d Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/generate-package=schema.png differ diff --git a/17/umbraco-cms/extending/packages/images/hitting-breakpoints.png b/17/umbraco-cms/extending/packages/images/hitting-breakpoints.png new file mode 100644 index 00000000000..2fbe4666e6e Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/hitting-breakpoints.png differ diff --git a/17/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png b/17/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png new file mode 100644 index 00000000000..48ee6810320 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/installed-package-leftovers-backoffice.png differ diff --git a/17/umbraco-cms/extending/packages/images/installed-package.png b/17/umbraco-cms/extending/packages/images/installed-package.png new file mode 100644 index 00000000000..715cf1f9bcb Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/installed-package.png differ diff --git a/17/umbraco-cms/extending/packages/images/nuget-installing-options.png b/17/umbraco-cms/extending/packages/images/nuget-installing-options.png new file mode 100644 index 00000000000..95d91944f82 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/nuget-installing-options.png differ diff --git a/17/umbraco-cms/extending/packages/images/nuget-package-in-manager.png b/17/umbraco-cms/extending/packages/images/nuget-package-in-manager.png new file mode 100644 index 00000000000..d5e1b3b80a5 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/nuget-package-in-manager.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-cli-command.png b/17/umbraco-cms/extending/packages/images/package-cli-command.png new file mode 100644 index 00000000000..e763915d62b Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-cli-command.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-custom-folder.png b/17/umbraco-cms/extending/packages/images/package-custom-folder.png new file mode 100644 index 00000000000..6d6d28f8af8 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-custom-folder.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-default-location.png b/17/umbraco-cms/extending/packages/images/package-default-location.png new file mode 100644 index 00000000000..0e53c020cae Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-default-location.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-files-list.png b/17/umbraco-cms/extending/packages/images/package-files-list.png new file mode 100644 index 00000000000..b3d5b4843ed Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-files-list.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-install-attended.png b/17/umbraco-cms/extending/packages/images/package-install-attended.png new file mode 100644 index 00000000000..c6f31569b02 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-install-attended.png differ diff --git a/17/umbraco-cms/extending/packages/images/package-options.gif b/17/umbraco-cms/extending/packages/images/package-options.gif new file mode 100644 index 00000000000..0bd1a81695f Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-options.gif differ diff --git a/17/umbraco-cms/extending/packages/images/package-properties.png b/17/umbraco-cms/extending/packages/images/package-properties.png new file mode 100644 index 00000000000..b7fb1b0d7f5 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/package-properties.png differ diff --git a/17/umbraco-cms/extending/packages/images/property-editor.png b/17/umbraco-cms/extending/packages/images/property-editor.png new file mode 100644 index 00000000000..7b049f578ca Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/property-editor.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-content.png b/17/umbraco-cms/extending/packages/images/removing-content.png new file mode 100644 index 00000000000..3fa0db3b6ad Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-content.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-datatypes.png b/17/umbraco-cms/extending/packages/images/removing-datatypes.png new file mode 100644 index 00000000000..7cd36ad62eb Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-datatypes.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-document-types.png b/17/umbraco-cms/extending/packages/images/removing-document-types.png new file mode 100644 index 00000000000..40d0ad2a49d Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-document-types.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-media.png b/17/umbraco-cms/extending/packages/images/removing-media.png new file mode 100644 index 00000000000..160ccfac9f6 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-media.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-partials.png b/17/umbraco-cms/extending/packages/images/removing-partials.png new file mode 100644 index 00000000000..1fc93d8ccaa Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-partials.png differ diff --git a/17/umbraco-cms/extending/packages/images/removing-templates.png b/17/umbraco-cms/extending/packages/images/removing-templates.png new file mode 100644 index 00000000000..08beb8e2c15 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/removing-templates.png differ diff --git a/17/umbraco-cms/extending/packages/images/select-files-for-package.png b/17/umbraco-cms/extending/packages/images/select-files-for-package.png new file mode 100644 index 00000000000..d059e30fe7d Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/select-files-for-package.png differ diff --git a/17/umbraco-cms/extending/packages/images/seochecker-after-removal.png b/17/umbraco-cms/extending/packages/images/seochecker-after-removal.png new file mode 100644 index 00000000000..9eb77e23309 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/seochecker-after-removal.png differ diff --git a/17/umbraco-cms/extending/packages/images/seochecker-app-plugins.png b/17/umbraco-cms/extending/packages/images/seochecker-app-plugins.png new file mode 100644 index 00000000000..b2b2ec0b92c Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/seochecker-app-plugins.png differ diff --git a/17/umbraco-cms/extending/packages/images/seochecker-content-section.png b/17/umbraco-cms/extending/packages/images/seochecker-content-section.png new file mode 100644 index 00000000000..5c83b0d11e6 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/seochecker-content-section.png differ diff --git a/17/umbraco-cms/extending/packages/images/specify-version-info.png b/17/umbraco-cms/extending/packages/images/specify-version-info.png new file mode 100644 index 00000000000..ece295fecdb Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/specify-version-info.png differ diff --git a/17/umbraco-cms/extending/packages/images/steppingThroughCode.png b/17/umbraco-cms/extending/packages/images/steppingThroughCode.png new file mode 100644 index 00000000000..2edb08c90e1 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/steppingThroughCode.png differ diff --git a/17/umbraco-cms/extending/packages/images/team-link.png b/17/umbraco-cms/extending/packages/images/team-link.png new file mode 100644 index 00000000000..61008aef4e3 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/team-link.png differ diff --git a/17/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png b/17/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png new file mode 100644 index 00000000000..b63cc056930 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/uninstalling-via-nuget-package-manager.png differ diff --git a/17/umbraco-cms/extending/packages/images/valueconnector.gif b/17/umbraco-cms/extending/packages/images/valueconnector.gif new file mode 100644 index 00000000000..40948d682f1 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/valueconnector.gif differ diff --git a/17/umbraco-cms/extending/packages/images/vs-cleaning-solution.png b/17/umbraco-cms/extending/packages/images/vs-cleaning-solution.png new file mode 100644 index 00000000000..435e2505b06 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/vs-cleaning-solution.png differ diff --git a/17/umbraco-cms/extending/packages/images/zip-package-contents.png b/17/umbraco-cms/extending/packages/images/zip-package-contents.png new file mode 100644 index 00000000000..9350caff0ed Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/zip-package-contents.png differ diff --git a/17/umbraco-cms/extending/packages/images/zip-package-v9.png b/17/umbraco-cms/extending/packages/images/zip-package-v9.png new file mode 100644 index 00000000000..169bbfb1591 Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/zip-package-v9.png differ diff --git a/17/umbraco-cms/extending/packages/images/zip-package.png b/17/umbraco-cms/extending/packages/images/zip-package.png new file mode 100644 index 00000000000..0ec18b86ceb Binary files /dev/null and b/17/umbraco-cms/extending/packages/images/zip-package.png differ diff --git a/17/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md b/17/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md new file mode 100644 index 00000000000..e132651cd2e --- /dev/null +++ b/17/umbraco-cms/extending/packages/installing-and-uninstalling-packages.md @@ -0,0 +1,189 @@ +--- +description: >- + The process of installing and, in turn, uninstalling packages in your Umbraco + CMS website. +--- + +# Installing and Uninstalling Packages + +This article will cover the process of installing as well as uninstalling packages from your Umbraco CMS website. + +## Installing packages + +In the Umbraco Backoffice, you will find a **Packages** section that displays the [Umbraco Marketplace](https://marketplace.umbraco.com/). From here you can browse all community-made as well as official Umbraco packages for the Umbraco CMS. + +![Backoffice - Packages section](images/backoffice-packages-section.png) + +Navigating to a specific package in the section will present you with an overview of the package, as well as an install snippet for NuGet CLI. + +![Backoffice - Starter Kit package](images/backoffice-packages-section-package.png) + +The packages can be installed by using: + +* **NuGet Package Manager** in Visual Studio +* **Package Manager Console** in Visual Studio +* .NET CLI (usually accessible from the terminal/command prompt of your system) + +For example, to install the StarterKit package for the Umbraco CMS the command would be: + +`dotnet add package Umbraco.TheStarterKit` + +Navigating to the NuGet Package Manager in Visual Studio is more visual, and gives you an overview of already installed packages. + +![Visual Studio - nuget packages manager](images/nuget-installing-options.png) + +The Package Manager has an integrated search function that allows you to find any public NuGet package and install it on the project. + +![Visual Studio - finding The Starter Kit](images/nuget-package-in-manager.png) + +Once the package has been installed, it will show up under the **Packages** section in the backoffice, under **Installed** tab. + +![Backoffice - installed packages](../../../../10/umbraco-cms/extending/packages/images/backoffice-installed-packages.png) + +## Uninstalling packages + +Uninstalling packages is not always as straightforward as installing them. + +In this section, we will provide two examples of uninstalling a package - the StarterKit package and the SEOChecker package. + +### Uninstalling packages like the StarterKit + +{% hint style="info" %} +Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply. +{% endhint %} + +The Starter Kit provides you with a boilerplate website solution to build upon. The package installs Document Types, Templates, media, content, and everything else needed to set up a small website. There is little custom code/functionality involved which is usually the case for such starter kit or sample-site packages. + +To uninstall a package, either run a command or use the NuGet Package Manager in Visual Studio. + +`dotnet remove package Umbraco.TheStarterKit` + +![Visual Studio - uninstalling via Package Manager](images/uninstalling-via-nuget-package-manager.png) + +It is recommended to clean the solution after removing any package. This can be done by right-clicking the project in Visual Studio and choosing the _Clean_ option, or using the `dotnet clean` command. + +![Visual Studio - clean solution](images/vs-cleaning-solution.png) + +#### Removing package leftovers from the backoffice + +With packages like the StarterKit, the process does not end there. While the package is gone, content - and everything else needed for the website - is still available in the backoffice. To fully remove this kind of package, additional steps are needed. + +
+ +Remove content provided by the package + +There is no universal way to tell what content comes from a package, and what content is custom-made. In the Content section, delete individual nodes accordingly. If the goal is to fully remove the package and clean the site, all the content can be removed (and the recycle bin emptied). + +Backoffice - removing content + +
+ +
+ +Remove media provided by the package + +Similar to content, media also might have to be removed. + +Backoffice - removing media + +
+ +
+ +Remove Document Types + +Document Types can be removed from the **Settings** section. If fully removing the package, all Document Types can be deleted, as there are no default Document Types in a clean-slate Umbraco installation. + +Backoffice - removing document types + +
+ +
+ +Removing Data Types + +As opposed to Document Types, there are some Data Types that are available out of the box when Umbraco is installed. It is not recommended to remove them. The safe approach is to delete any item that starts with a Document Type prefix and includes multiple dashes. That is the default naming convention for new configurations of Data Types (Example: "Blog - How many posts should be shown - Slider") + +Backoffice - removing data types + +
+ +
+ +Removing Templates + +No Templates are available out of the box in a new installation. If cleaning up after a package, it would be okay to delete all that are present + +Backoffice - removing templates + +
+ +
+ +Removing Partial Views + +Out of the box, there are a few views available in the `blocklist` and `grid` folders. Everything else can theoretically be removed. + +Backoffice - removing partial views + +
+ +
+ +Cleaning leftover files on disk + +Some packages might reference other items. For example, installing the StarterKit also adds `Bergmania.OpenStreetMap` to your project. That component will show up as installed in the backoffice even after uninstalling the NuGet package. + +Backoffice - Packages section - leftover dependency + +In many cases, custom dashboards, editors, and scripts are left in the `App_Plugins` folder after a package has been uninstalled via NuGet. These files also have to be deleted manually. + +Visual Studio - App Plugins leftover files + +
+ +### Uninstalling packages like the SEOChecker + +{% hint style="info" %} +Keep in mind that this particular guide targets a specific package. There are many packages out there, and each one is different. The exact steps presented here might not work the exact same way for all the packages, though the general approach should still apply. +{% endhint %} + +More advanced packages that add functionality on top of Umbraco, usually rely on providing custom, compiled code. That being said, many of such packages also implement custom Sections, Dashboards, editors, and views. + +In this example, we will be using the SEOChecker package. This package allows developers of the site to add custom properties to Document Types used to track search engine optimization practices. + +An example use case of the SEOChecker property on a Document Type, as presented in the Content section: + +![SEOChecker in content](../../../../10/umbraco-cms/extending/packages/images/seochecker-content-section.png) + +To uninstall the SEOChecker from a website, the first step is to remove the package via a `dotnet` command or use the NuGet Package Manager. + +The following command can be used for uninstalling the package: + +`dotnet remove package SEOChecker` + +After that, cleaning the solution is recommended. + +![Visual Studio - clean solution](images/vs-cleaning-solution.png) + +
+ +Cleaning leftover files on disk + +While uninstalling the package would remove most of the custom code, the `App_Plugins` folder has to be cleaned manually. + +SEOChecker files in App Plugins + +Removing _seochecker_ folder from `App_Plugins` will clean up the leftover backoffice section and dashboards. + +
+ +## Consequences of removing packages + +If content on the website relies on having a custom Property Editor or a data source installed, those properties will default to a `label` Data Type. All previously saved content in the property will in turn be converted to a string. + +In the case of the SEOChecker, the custom property added from the package would look like this after all the package files have been removed: + +![The SEOChecker in Content after removing the package](../../../../10/umbraco-cms/extending/packages/images/seochecker-after-removal.png) + +Depending on the packages and the implementation, rendering of content from custom editors, or any frontend functionality dependent on external code, might not work correctly. It is always recommended to inspect the frontend of the site after removing any packages. diff --git a/17/umbraco-cms/extending/packages/language-files-for-packages.md b/17/umbraco-cms/extending/packages/language-files-for-packages.md new file mode 100644 index 00000000000..b83eab49765 --- /dev/null +++ b/17/umbraco-cms/extending/packages/language-files-for-packages.md @@ -0,0 +1,36 @@ +--- +description: >- + Information on how to use language files to make your Umbraco package UI + support multiple languages +--- + +# Language file for packages + +If you want your package to be available in different languages, you can use the existing localizations from Umbraco or register your own localizations. The localizations are written as a key-value pair pattern. + +To register localizations to a language, you must add a new manifest to the Extension API. The manifest can be added through the `umbraco-package.json` file like this: + +{% code title="umbraco-package.json" lineNumbers="true" %} +``` +``` +{% endcode %} + +```json +{ + ... + "name": "MyPackage", + "extensions": [ + { + "type": "localization", + "alias": "MyPackage.Localize.En", + "name": "English", + "meta": { + "culture": "en" + }, + "js": "/App_Plugins/MyPackage/Localization/en-us.js" + } + ] +} +``` + +Read the [UI Localization documentation](../../customizing/foundation/localization.md) to learn in-depth on how you can use languages in your packages and Umbraco in general. diff --git a/17/umbraco-cms/extending/packages/listing-on-marketplace.md b/17/umbraco-cms/extending/packages/listing-on-marketplace.md new file mode 100644 index 00000000000..2cc27f0408c --- /dev/null +++ b/17/umbraco-cms/extending/packages/listing-on-marketplace.md @@ -0,0 +1,11 @@ +--- +description: Information on how to list your package on the Umbraco Marketplace. +--- + +# Listing on the Umbraco Marketplace + +The [Umbraco Marketplace](https://marketplace.umbraco.com) is a website built and maintained by Umbraco HQ to support searching and reviewing packages. + +It lists all commercial and open-source packages that the community has made available on NuGet. + +More information, including details of the steps for listing, are available at the dedicated [documentation space for the Marketplace](https://docs.umbraco.com/umbraco-dxp/marketplace/introduction). diff --git a/17/umbraco-cms/extending/packages/maintaining-packages.md b/17/umbraco-cms/extending/packages/maintaining-packages.md new file mode 100644 index 00000000000..562e0edf678 --- /dev/null +++ b/17/umbraco-cms/extending/packages/maintaining-packages.md @@ -0,0 +1,50 @@ +--- +description: >- + Once you've created and published your package, here is what's involved in + it's ongoing maintenance +--- + +# Maintaining packages + +Once you've created and published your package, what's involved in its ongoing maintenance? + +## Updating with new Umbraco major versions + +Umbraco will regular release update to the CMS as patch or minor versions. These are verified to be backwards compatible. As such there's no expectation that a package may break when a new version of this type comes out. + +When a new major version of Umbraco is released, there will be breaking changes. You should test your package on this latest version to confirm it still works. Unless there's been a significant change to the CMS, many packages will continue to work with the new major version without any update. However you may be using a service or API that has undergone a breaking change. + +If this happens, the changes will be documented and you should be able to update your code, recompile and test. After that you can release a new major version of your own package. + +Even if there are no breaking changes that affect you, it's worth also looking for any code you using that is marked as obsolete. Umbraco will obsolete public methods or constructors that are expected to be removed in a future major version. + +### Referencing Umbraco dependencies + +When creating a package with Umbraco you will be taking a dependency on at least one Umbraco package. You will do this in the `.csproj` file for your package: + +```xml + +``` + +As indicated, this states the package is compatible with Umbraco 10 and any future version. This would allow the developer to install the package into an Umbraco 12 or 13 solution for example. + +If you want to maintain tighter control over this, you can specify an upper bound, like this: + +```xml + +``` + +This states that the package is compatible with Umbraco 10, 11 and 12, but not 13. Thus it prevents anyone installing your package into an Umbraco solution that you haven't verified compatibility with. Once you have, you can increase the bound or otherwise update the dependent Umbraco version as appropriate. + +## Manage feature requests and issues + +If you want to encourage feedback, feature requests, and issue reports then you should make available an issue tracker. + +This can be [provided as information about your package](https://docs.umbraco.com/umbraco-dxp/marketplace/listing-your-package) and will be linked from your package's page on the Umbraco Marketplace. Specifically you should populate the `IssueTrackerUrl` field. + +## Package no longer required? + +After some time it could be that your package should no longer be used. Perhaps it is now too old, or it has been superseded by another one that you recommend instead. + +You can indicate this by [deprecating your package on NuGet](https://learn.microsoft.com/en-us/nuget/nuget-org/deprecate-packages). + diff --git a/17/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md b/17/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md new file mode 100644 index 00000000000..ec2f5295f35 --- /dev/null +++ b/17/umbraco-cms/extending/packages/packages-on-umbraco-cloud.md @@ -0,0 +1,44 @@ +--- +description: Things to consider for package development and usage in Umbraco Cloud +--- + +# Packages on Umbraco Cloud + +If you want to use or develop packages for Umbraco Cloud there are a few things to consider and be aware of. The two most important things to know about are + +* [How you should store data on Cloud](packages-on-umbraco-cloud.md#storing-data) +* [Using custom property editors with Deploy](packages-on-umbraco-cloud.md#valueconnectors) + +## Storing data + +When developing a package you will sometimes store data, this can be data in many forms - Umbraco schema / content, package settings, etc. + +When you develop a package for Umbraco Cloud there are a few things to be aware of when storing data, mainly whether you want that data to be specific to 1 environment or more. + +Let's take a look at the most common ways of storing data in packages - and what to watch out for on Cloud. + +### Migrations + +A [migration](../database.md) is some code that you run as part of a migration plan. That migration plan has an ID that is stored in the database (in the KeyValue table). This means that when you add new migrations Umbraco will only execute the ones that came after the one with the stored ID. The most important difference between a migration and a package action is when they are initialized. A package action runs on package install and uninstall, whereas a migration will run whenever you want it to run, see below for common examples. + +As migration runs are stored in the database of the site it also means that they will run on each environment you trigger them on. The most common way to trigger a migration is to include them in a [composer](../../implementation/composing.md), which will ensure they run on site startup. This means any commands you have in your migration will automatically run when the site starts up. When your package code is pushed to a new environment it will run them from the beginning on that environment as no ID is saved in the database. + +This is normally a good thing. However if you generate any Umbraco schema then Umbraco Deploy will automatically create [UDA files](https://docs.umbraco.com/umbraco-cloud/set-up/power-tools/generating-uda-files) based on that schema, and commit them to source control. This means that when you deploy all your files to the next environment the migration will run again, create duplicates and generate duplicate UDA files, which could end up causing a lot of issues. + +You could consider creating Umbraco schema only during a package action, and then running things like creating database tables in migrations. Another good workaround could be to not run the migrations in a composer, but rather create a dashboard for the package where the user can choose which migrations to run themselves. The [Articulate package](https://github.com/Shazwazza/Articulate/blob/master/build/packageManifest.xml#L613) has an example of this. + +### Creating files + +You may sometimes choose to save data in a file. Could be a separate config file for your package or a [config transform file](https://docs.umbraco.com/umbraco-cloud/set-up/config-transforms) to add an app setting to the web.config. If you do this be aware of two things: + +1. If these files are generated on a Cloud environment they will not be stored in source control, and will be overwritten on next deployment. They need to be installed locally, committed to source control and then pushed up to the Cloud environments. We have an [existing feature request](../../reference/mapping.md) on allowing package creators to commit their files directly on Cloud, and it is possible to do so currently but not in a supported way, and it may change suddenly. +2. If you need the content of the files to be different on the different environments you will need to use environment specific [config transforms](https://docs.umbraco.com/umbraco-cloud/set-up/config-transforms). + +## Value connectors + +A value connector is an extension to Umbraco Deploy that allows you to transform data when you deploy content of any kind between environments. When it comes to packages, one reason you need to consider these if you are supporting deploying content properties that rely on integer IDs. Content and other Umbraco data has two identifiers - an integer and a GUID. The GUID is consistent between environments but the integer ID is not. As such, if transferring content between environments and relying on integer IDs, you'll need to include a value connector to transform the value. + +They also manage dependencies for property data. If you save an ID of an image in your property editor, you can make sure the related image media item is transferred too. + +You can read more about value connectors and other extensions to Umbraco Deploy [here](https://docs.umbraco.com/umbraco-deploy/getting-started/extending). + diff --git a/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png b/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png new file mode 100644 index 00000000000..d5465050e54 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8 (1).png differ diff --git a/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png b/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png new file mode 100644 index 00000000000..d5465050e54 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/add-custom-section-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/add-custom-section.png b/17/umbraco-cms/extending/section-trees/images/add-custom-section.png new file mode 100644 index 00000000000..56ab633a134 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/add-custom-section.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png b/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png new file mode 100644 index 00000000000..1ab9820f3bc Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8 (1).png differ diff --git a/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png b/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png new file mode 100644 index 00000000000..1ab9820f3bc Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/backoffice-search-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/backoffice-search.png b/17/umbraco-cms/extending/section-trees/images/backoffice-search.png new file mode 100644 index 00000000000..31c5f536067 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/backoffice-search.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png b/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png new file mode 100644 index 00000000000..6a8e9633af9 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8 (1).png differ diff --git a/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png b/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png new file mode 100644 index 00000000000..6a8e9633af9 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/custom-section-alias-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/custom-section-alias.png b/17/umbraco-cms/extending/section-trees/images/custom-section-alias.png new file mode 100644 index 00000000000..9cac915a1cb Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/custom-section-alias.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png b/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png new file mode 100644 index 00000000000..c1010a8dda1 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8 (1).png differ diff --git a/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png b/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png new file mode 100644 index 00000000000..c1010a8dda1 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/favouritethings-search-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/images/favouritethings-search.png b/17/umbraco-cms/extending/section-trees/images/favouritethings-search.png new file mode 100644 index 00000000000..9b297a84ac5 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/images/favouritethings-search.png differ diff --git a/17/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png b/17/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png new file mode 100644 index 00000000000..ac562758a4b Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/trees/images/delete-raindrops-on-roses-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png b/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png new file mode 100644 index 00000000000..c40ceb25a75 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-single-node-tree.png differ diff --git a/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png b/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png new file mode 100644 index 00000000000..9dcef2ad50c Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/trees/images/favourite-thing-custom-tree-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png b/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png new file mode 100644 index 00000000000..c6e99e95dc7 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree-v8.png differ diff --git a/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png b/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png new file mode 100644 index 00000000000..ada029e7947 Binary files /dev/null and b/17/umbraco-cms/extending/section-trees/trees/images/favourite-things-custom-tree.png differ diff --git a/17/umbraco-cms/extending/server-events.md b/17/umbraco-cms/extending/server-events.md new file mode 100644 index 00000000000..b2a95e0ef91 --- /dev/null +++ b/17/umbraco-cms/extending/server-events.md @@ -0,0 +1,118 @@ +--- +description: Describes server events emitted via a SignalR hub and available for consumption in the backoffice +--- + +# Server Events + +Umbraco registers a SignalR event hub that broadcasts events related to the update of entities. These can be used in the backoffice to respond to changes made by users other than the current editor. + +Each server event is triggered via a notification handler. So for example, when a document is saved, the `ContentSavedNotification` is published. This is handled by a class responsible for issuing a server event. + +Not all server events should be broadcast to all users. For example, if a user doesn't have access to the Media section, they shouldn't receive notifications on updates to media. For core entities, Umbraco uses the same permission system that defines access in the backoffice. In this way, only events appropriate for the currently logged in editor are exposed. + +## Event Information + +Each event emitted contains the following fields: + +- `EventType` - the event type, which might be `Created`, `Updated`, `Deleted` etc. +- `EventSource` - the event source, which might be `Document`, `Media` etc. +- `Key` - the unique GUID that identifies the entity changed. + +## Event Authorization + +The currently authorized user will have one or more claims indicating the access they have to different areas of the backoffice. When first connecting to the SignalR hub, these details are used to assign the user to one or more SignalR groups. + +Which groups they have access to is determined by the collection of registered `IEventSourceAuthorizer` instances. + +For example, there is a `DocumentEventAuthorizer` that ensures users with access to the documents (content) tree are assigned to the `Umbraco:CMS:Document` event source. As a result, when server events are emitted for documents, only those users with this access will receive them. + +## Extending Server Events + +Using the same patterns as the core CMS, server events for other entities defined in packages or custom solutions can be emitted. + +Firstly, a `IEventSourceAuthorizer` should be registered. This will likely hook into what you already have in place for controlling access to the backoffice section where the entity is managed. + +For example, if you had a `Product` entity managed in a custom CMS section, the authorizer might look like this: + +```csharp +using Microsoft.AspNetCore.Authorization; +using Umbraco.Cms.Core; +using Umbraco.Cms.Web.Common.Authorization; + +public class ProductEventAuthorizer : EventSourcePolicyAuthorizer +{ + public ProductEventAuthorizer(IAuthorizationService authorizationService) + : base(authorizationService) + { + } + + public override IEnumerable AuthorizableEventSources => ["Umbraco:Custom:Product"]; + + protected override string Policy => "TreeAccessProducts"; // Maps to an existing authorization policy + // used in an [Authorize] attribute. +} +``` + +The authorizer should be registered with Umbraco using something like the following, called from a composer, or otherwise in application start up: + +```csharp +public static IUmbracoBuilder AddCustomAuthorizers(this IUmbracoBuilder builder) +{ + builder.EventSourceAuthorizers() + .Append(); +} +``` + +You then need to emit the event from a notification handler which handles notifications published when the entity is updated. + +For example, assuming an existing `ProductSavedNotification` that is published with the product is saved: + +```csharp +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models.Entities; +using Umbraco.Cms.Core.Models.ServerEvents; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.ServerEvents; + +namespace Umbraco.Cms.Api.Management.ServerEvents; + +public class ProductServerEventSender : INotificationAsyncHandler +{ + private readonly IServerEventRouter _serverEventRouter; + + public ProductServerEventSender(IServerEventRouter serverEventRouter) => _serverEventRouter = serverEventRouter; + + public async Task HandleAsync(ProductSavedNotification notification, CancellationToken cancellationToken) => + await NotifySavedAsync(notification, "Umbraco:Custom:Product"); + + private async Task NotifySavedAsync(SavedNotification notification, string source) + where T : IEntity + { + foreach (T entity in notification.SavedEntities) + { + var eventModel = new ServerEvent + { + EventType = entity.CreateDate == entity.UpdateDate + ? Constants.ServerEvents.EventType.Created : Constants.ServerEvents.EventType.Updated, + Key = entity.Key, + EventSource = source, + }; + + await _serverEventRouter.RouteEventAsync(eventModel); + } + } +} +``` + +Again, the notification handler will need to be registered with Umbraco: + +```csharp +public static IUmbracoBuilder AddCustomEvents(this IUmbracoBuilder builder) +{ + builder.AddNotificationAsyncHandler(); +} +``` + + + diff --git a/17/umbraco-cms/fundamentals/backoffice/README.md b/17/umbraco-cms/fundamentals/backoffice/README.md new file mode 100644 index 00000000000..f4fc2f03fe2 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/README.md @@ -0,0 +1,147 @@ +--- +description: >- + Learn more about the Umbraco backoffice which is the admin side of your + Umbraco website +--- + +# Backoffice + +In this article you can learn more about the common terms and concepts that are used throughout the Umbraco backoffice. + +## [Login screen](login.md) + +When you go to the backoffice for the first time, you're presented with the login screen. + +![Login screen](images/login-backoffice-login-v14.png) + +[Read more about the login screen](login.md). + +## [Section](sections.md) + +A section in Umbraco is where you do specific tasks related to that section. For example Content, Settings and Users. You can navigate between the different sections of the backoffice by clicking the corresponding icon in the section menu. + +_The **Section menu** is the horizontal menu located on the top of the backoffice._ + +![Section](images/highlight-sections-v14.png) + +[Read more about the section menu](sections.md). + +## [Tree](../../customizing/section-trees.md) + +A tree is a hierarchical list of items related (and usually restricted) to a specific concept, like for example content or media. + +You can expand trees by clicking the side arrow ![Expand Node](images/expand-node-v14.png) to the left of the node. + +![Tree](images/highlight-tree-v14.png) + +[Read more about the Tree](../../customizing/section-trees.md) + +## Node + +A node is an item in a tree. Media section items appear as nodes in the Media tree, while pages and content are displayed in the Content tree, and so on. + +![Node](images/highlight-content-node-v14.png) + +## [Dashboards](../../customizing/extending-overview/extension-types/dashboard.md) + +A dashboard is the main view you are presented with when entering a section within the backoffice. It can be used to show valuable information to the users of the system. + +![Default dashboard in the Content section](images/highlight-dashboard-v14.png) + +[Read more about Dashboards](../../customizing/extending-overview/extension-types/dashboard.md) + +## Editor + +An editor is what you use to edit different items within the backoffice. There are editors specific to editing stylesheets, there are editors for editing Partial Views, and so forth. + +## [Content](../data/defining-content/) + +Content is what you find in the Content section. Each item in the tree is called a **content node**. Each content node in the content tree consists of different fields, and each of them is defined by a Document Type. + +![Content](images/highlight-content-v14.png) + +[Read more about Content](../data/defining-content/) + +## Document Type + +Document Types define the types of content nodes that backoffice users can create in the content tree. Each Document Type contains different properties. Each property has a specific Data Type for example text or number. + +![Document Types](images/document-types-v14.png) + +### Properties + +Every Document Type has properties. These are the fields that the content editor is allowed to edit for the content node. + +![Document Type Properties](images/document-type-properties-v14.png) + +### [Data Type](../data/data-types/) + +Each Document Type property has a Data Type that defines the type of input of that property. Data Types reference a Property Editor and are configured in the Umbraco backoffice in the Settings section. A Data Type can be something basic (text string, number, true/false) or more complex (multi-node tree picker, image cropper, etc). + +![Data Types](images/data-types-v14.png) + +[Read more about Data Types](../data/data-types/) + +### [Property Editors](property-editors/) + +A property editor is a view used by Data Types to insert content into Umbraco. An example of a property editor is the _Textarea_. It's possible to have many Textarea Data Types with different settings that all use the Textarea property editor. + +![Property Editor](images/property-editor-v14.png) + +[Read more about Property Editors](property-editors/) + +## [Media](../data/creating-media/) + +Media items are used to store assets like images and video within the Media section and can be referenced from your content. + +![Media](images/Media-v14.png) + +[Read more about Media](../data/creating-media/) + +### Media Types + +Media Types are similar to Document Types in Umbraco, except they are specifically for media items in the Media section. + +Umbraco includes the following default Media Types - **Article**, **Audio**, **File**, **Folder**, **Image**, **Vector Graphics (SVG)**, and **Video**. + +![Media Types](images/Media-Type-v14.png) + +## [Members](../data/members.md) + +A member is someone who has access to signup, register, and login into your **public website** and is not to be confused with Users. + +![Members](images/Members-v14.png) + +[Read more about Members](../data/members.md) + +### Member Types + +Similar to a Document Type and a Media Type. You are able to define custom properties to store on a member such as Twitter username or website URL. + +![Member Types](images/Member-Types-v14.png) + +## [Templates](../design/templates/) + +A Template is where you define the HTML markup of your website and also where you output the data from your content nodes. + +![Templates](images/template-v14.png) + +[Read more about Templates](../design/templates/) + +## Packages + +A package is the Umbraco term for an add-on or plugin used to extend the core functionalities in Umbraco. The packages can be found on the [Umbraco Marketplace](https://marketplace.umbraco.com/), and the can also be browsed directly in the backoffice of the Umbraco CMS. + +![Packages](images/packages-v14.png) + +## Users + +A user is someone who has access to the **Umbraco backoffice** and is not to be confused with Members. When Umbraco has been installed a user will automatically be generated with the login (email) and password entered during installation. Users can be created, edited, and managed in the User section. + +![Users](images/Users-v14.png) + +## [Document Blueprints](document-blueprints.md) + +Document Blueprint provide a blueprint for content nodes based on an existing node. + +![Document Blueprint](images/document-blueprint-v16.png) diff --git a/17/umbraco-cms/fundamentals/backoffice/document-blueprints.md b/17/umbraco-cms/fundamentals/backoffice/document-blueprints.md new file mode 100644 index 00000000000..6f6d1ab3521 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/document-blueprints.md @@ -0,0 +1,99 @@ +--- +description: >- + Learn how to create and use Document Blueprints in Umbraco. +--- + +# Document Blueprints + +{% hint style="info" %} +Document Blueprints were previously called Content Templates. +{% endhint %} + +## Document Blueprints Overview + +A Document Blueprint allows editors to preconfigure a content node. It serves as a reusable starting point when creating new content. + +### Method 1 – Create a Document Blueprint from the Content Section + +{% hint style="warning" %} +Before using this method, make sure you have already [created some content](../data/defining-content/README.md#3-creating-the-content). +{% endhint %} + +1. Go to the **Content** section and select an existing content node. + +![Content-Menu](images/content-menu-DB.png) + +2. Click the **...** menu next to the node and choose **Create Document Blueprint**. + +![Action Button](images/action-menu-DB.png) + +3. Enter a **Name** for the new blueprint. + +![Document Blueprint Name Field](images/Name-Content-Template-DB.png) + +4. Click **Save**. + +The new blueprint will appear under the **Document Blueprints** folder in the **Settings** section. + +![New Document Blueprint](images/Find-Content-Template-DB.png) + +{% hint style="info" %} +If you don’t see the new blueprint, try refreshing your browser. +{% endhint %} + +### Method 2 – Create a Document Blueprint from the Settings Section + +1. Go to the **Settings** section. + +2. Click the **...** menu next to the **Document Blueprints** tree. + +3. Select **Create...**. + +![Create Document Blueprint](images/Create-Content-Template-DB.png) + +4. Choose the Document Type you want to base the blueprint on. + +![Select Content Type](images/Content-Type-DB.png) + +{% hint style="warning" %} +You can only create Document Blueprints from **Document Types** or **Document Types with Templates**. +{% endhint %} + +5. Enter a **Name** for the blueprint. +6. Click **Save**. + +The new blueprint will appear under the **Document Blueprints** folder in the **Settings** section. + +### Edit a Document Blueprint + +To edit an existing document blueprint, follow these steps: + +1. Go to the **Settings** section. +2. Open the **Document Blueprints** folder. +3. Select the blueprint you want to edit. +4. Make your changes. +5. Click **Save**. + +![Edit Document Blueprint](images/Edit-Content-Template-DB.png) + +### Use a Document Blueprint + +Once you have created a document blueprint, you can use it to create new content nodes. + +To use a document blueprint, follow these steps: + +1. Go to the **Content** section. +2. Click the **...** menu next to the root node and select **Create**. + +![Create From Template](images/Create-From-Template-DB.png) + +3. Select the **Document Type** that has an associated blueprint. + +![Select the Document Type](images/select-doc-type-DB.png) + +4. Choose how to create the new content: + + * Use the Document Blueprint + * Start with a blank node + +![Select Template](images/Select-Template-DB.png) diff --git a/17/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png new file mode 100644 index 00000000000..fd1aa38c909 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/01-Content-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png new file mode 100644 index 00000000000..9a4c63c5b7a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/02-Actions-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png new file mode 100644 index 00000000000..30bd53bd31c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/03-Name-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png new file mode 100644 index 00000000000..92bda986ff2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/04-Save-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png new file mode 100644 index 00000000000..a27e7fccade Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/05-Find-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png new file mode 100644 index 00000000000..28fc44c2d47 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/06-Edit-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png new file mode 100644 index 00000000000..b337fcbdd64 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/07-Settings-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png new file mode 100644 index 00000000000..1e02b91ac87 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/08-Create-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png b/17/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png new file mode 100644 index 00000000000..1667a1004e1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/09-Select-Content-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png new file mode 100644 index 00000000000..3eacba37b32 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/10-Save-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png new file mode 100644 index 00000000000..ed641e4ff90 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/11-Find-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png new file mode 100644 index 00000000000..147b376c44c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/12-Create-From-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png new file mode 100644 index 00000000000..904351ebe5e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/13-Select-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Add-ons.png b/17/umbraco-cms/fundamentals/backoffice/images/Add-ons.png new file mode 100644 index 00000000000..82c43f933e1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Add-ons.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Allowing-Variance-on-properties.png b/17/umbraco-cms/fundamentals/backoffice/images/Allowing-Variance-on-properties.png new file mode 100644 index 00000000000..b9cb76264f6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Allowing-Variance-on-properties.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png b/17/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png new file mode 100644 index 00000000000..e03a4c893e8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Assign-Access-Languages.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png b/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png new file mode 100644 index 00000000000..949ae88fff5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorConfigurationProgramatically.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png b/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png new file mode 100644 index 00000000000..4edfd5aba87 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/BlockEditorContentCreated.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Content-Type-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Content-Type-DB.png new file mode 100644 index 00000000000..445123db8cc Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Content-Type-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Content-Type.png b/17/umbraco-cms/fundamentals/backoffice/images/Content-Type.png new file mode 100644 index 00000000000..149c0b225f6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Content-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Content.png b/17/umbraco-cms/fundamentals/backoffice/images/Content.png new file mode 100644 index 00000000000..9ab10d1fe04 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template-DB.png new file mode 100644 index 00000000000..2d5a61c6705 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template.png new file mode 100644 index 00000000000..08207f2a985 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Create-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template-DB.png new file mode 100644 index 00000000000..3f38a1b363c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template.png new file mode 100644 index 00000000000..c250d8ca953 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Create-From-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Developer.png b/17/umbraco-cms/fundamentals/backoffice/images/Developer.png new file mode 100644 index 00000000000..ce155b66cc5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Developer.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Dropdown-DataType.png b/17/umbraco-cms/fundamentals/backoffice/images/Dropdown-DataType.png new file mode 100644 index 00000000000..6785734474b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Dropdown-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template-DB.png new file mode 100644 index 00000000000..c9b7e65f4c5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template.png new file mode 100644 index 00000000000..37e7d82f950 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Edit-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/English_get.png b/17/umbraco-cms/fundamentals/backoffice/images/English_get.png new file mode 100644 index 00000000000..70e3950dff0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/English_get.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template-DB.png new file mode 100644 index 00000000000..e27e783ec79 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template.png new file mode 100644 index 00000000000..8020ec1ba39 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Find-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Find-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Find-Template.png new file mode 100644 index 00000000000..32ec568f82b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Find-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Forms.png b/17/umbraco-cms/fundamentals/backoffice/images/Forms.png new file mode 100644 index 00000000000..6dfdf03de1b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Forms.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Help.png b/17/umbraco-cms/fundamentals/backoffice/images/Help.png new file mode 100644 index 00000000000..bf96869ef08 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Help.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif b/17/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif new file mode 100644 index 00000000000..b24121d92ba Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Infinite-editing.gif differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Media-Type-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/Media-Type-v14.png new file mode 100644 index 00000000000..bd5e047e924 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Media-Type-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Media-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/Media-v14.png new file mode 100644 index 00000000000..a65bda6939d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Media-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Media.png b/17/umbraco-cms/fundamentals/backoffice/images/Media.png new file mode 100644 index 00000000000..77f0746531b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Media.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Member-Types-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/Member-Types-v14.png new file mode 100644 index 00000000000..0a7147a93d6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Member-Types-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Members-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/Members-v14.png new file mode 100644 index 00000000000..9ee60709619 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Members-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Members.png b/17/umbraco-cms/fundamentals/backoffice/images/Members.png new file mode 100644 index 00000000000..d805f89a211 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Members.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template-DB.png new file mode 100644 index 00000000000..3d8b5160866 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template.png new file mode 100644 index 00000000000..d04b58c18e7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Name-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Save-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Save-Content-Template.png new file mode 100644 index 00000000000..84b849c80e3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Save-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Save-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Save-Template.png new file mode 100644 index 00000000000..3d3efe9bdc8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Save-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Select-Template-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/Select-Template-DB.png new file mode 100644 index 00000000000..ed2c506a6cd Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Select-Template-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Select-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/Select-Template.png new file mode 100644 index 00000000000..ffce97142d4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Select-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Settings-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/Settings-Menu.png new file mode 100644 index 00000000000..fe0112dcef3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Settings-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Settings.png b/17/umbraco-cms/fundamentals/backoffice/images/Settings.png new file mode 100644 index 00000000000..3c4a206e0a2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Users-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/Users-v14.png new file mode 100644 index 00000000000..7e73da5e53b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Users-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/Users.png b/17/umbraco-cms/fundamentals/backoffice/images/Users.png new file mode 100644 index 00000000000..d589c44c76f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/Users.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/action-menu-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/action-menu-DB.png new file mode 100644 index 00000000000..3de2584b7df Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/action-menu-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/action-menu.png b/17/umbraco-cms/fundamentals/backoffice/images/action-menu.png new file mode 100644 index 00000000000..a33cfb09ec6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/action-menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/adding-a-language.png b/17/umbraco-cms/fundamentals/backoffice/images/adding-a-language.png new file mode 100644 index 00000000000..e5bb43dc9c0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/adding-a-language.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/allow-variance.png b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance.png new file mode 100644 index 00000000000..5fed09efd7c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/allow-variance2.png b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance2.png new file mode 100644 index 00000000000..65f9a34c499 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance2.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png new file mode 100644 index 00000000000..828f73cdceb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/allow-variance_v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png b/17/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png new file mode 100644 index 00000000000..736a44a2f3e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/backoffice-login.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/content-menu-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/content-menu-DB.png new file mode 100644 index 00000000000..f63c1b8d6ce Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/content-menu-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/content-menu.png b/17/umbraco-cms/fundamentals/backoffice/images/content-menu.png new file mode 100644 index 00000000000..29e78f3e879 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/content-menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/data-types-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/data-types-v14.png new file mode 100644 index 00000000000..bc854bff954 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/data-types-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v14.png new file mode 100644 index 00000000000..1e5e38f5fe2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v16.png b/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v16.png new file mode 100644 index 00000000000..e2143cedd79 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/document-blueprint-v16.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/document-type-properties-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/document-type-properties-v14.png new file mode 100644 index 00000000000..1a3a99baaca Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/document-type-properties-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/document-types-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/document-types-v14.png new file mode 100644 index 00000000000..f0f76e63f64 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/document-types-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/expand-node-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/expand-node-v14.png new file mode 100644 index 00000000000..de3b284929b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/expand-node-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg b/17/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg new file mode 100644 index 00000000000..fd3509507a6 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/images/has-unpublished-version.svg @@ -0,0 +1 @@ + diff --git a/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-node-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-node-v14.png new file mode 100644 index 00000000000..45db35b3703 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-node-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-v14.png new file mode 100644 index 00000000000..8646513184d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/highlight-content-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard-v14.png new file mode 100644 index 00000000000..39adf28fa20 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/highlight-dashboard-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/highlight-sections-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/highlight-sections-v14.png new file mode 100644 index 00000000000..52eb170b799 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/highlight-sections-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/highlight-tree-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/highlight-tree-v14.png new file mode 100644 index 00000000000..aa086ceb376 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/highlight-tree-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png b/17/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png new file mode 100644 index 00000000000..7159ba8b58a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/invariant-property-locked.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/is-container.svg b/17/umbraco-cms/fundamentals/backoffice/images/is-container.svg new file mode 100644 index 00000000000..b43024c3d0e --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/images/is-container.svg @@ -0,0 +1 @@ + diff --git a/17/umbraco-cms/fundamentals/backoffice/images/languages.png b/17/umbraco-cms/fundamentals/backoffice/images/languages.png new file mode 100644 index 00000000000..3820e0cae49 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/languages.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/languages_v10.png b/17/umbraco-cms/fundamentals/backoffice/images/languages_v10.png new file mode 100644 index 00000000000..d8e66c08b24 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/languages_v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/locked-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/locked-v14.png new file mode 100644 index 00000000000..22f7bee6520 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/locked-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/locked.svg b/17/umbraco-cms/fundamentals/backoffice/images/locked.svg new file mode 100644 index 00000000000..782eb1006fb --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/images/locked.svg @@ -0,0 +1 @@ + diff --git a/17/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login-v14.png new file mode 100644 index 00000000000..dc92982be28 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/login-backoffice-login-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp.png new file mode 100644 index 00000000000..47be9e4ce2d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type.png new file mode 100644 index 00000000000..82e3a4f40e9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root.png new file mode 100644 index 00000000000..c9cdfa8254e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_origin.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_origin.png new file mode 100644 index 00000000000..401c38157a5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_origin.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_overview.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_overview.png new file mode 100644 index 00000000000..d482460dd58 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_overview.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_steps.png b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_steps.png new file mode 100644 index 00000000000..e1e0ad3db83 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/mntp_node_type_dynamic_root_steps.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/packages-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/packages-v14.png new file mode 100644 index 00000000000..e1ab01a2da0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/packages-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/property-editor-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/property-editor-v14.png new file mode 100644 index 00000000000..6553f609e08 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/property-editor-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/protected.svg b/17/umbraco-cms/fundamentals/backoffice/images/protected.svg new file mode 100644 index 00000000000..3aab0c725f5 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/images/protected.svg @@ -0,0 +1 @@ + diff --git a/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png b/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png new file mode 100644 index 00000000000..246bb98a467 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections2.png b/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections2.png new file mode 100644 index 00000000000..3244d145125 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/sections-highlight-sections2.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/select-doc-type-DB.png b/17/umbraco-cms/fundamentals/backoffice/images/select-doc-type-DB.png new file mode 100644 index 00000000000..4b2d60786fd Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/select-doc-type-DB.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/template-v14.png b/17/umbraco-cms/fundamentals/backoffice/images/template-v14.png new file mode 100644 index 00000000000..7330f070a60 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/template-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/timeout-screen.jpg b/17/umbraco-cms/fundamentals/backoffice/images/timeout-screen.jpg new file mode 100644 index 00000000000..c57857c7a3d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/timeout-screen.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg new file mode 100644 index 00000000000..fdac204aafe Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_dashboard.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg new file mode 100644 index 00000000000..6627a757b7c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_login.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg new file mode 100644 index 00000000000..b1dc1cd708e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_sections.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg new file mode 100644 index 00000000000..6de9e5a00d6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/umbraco7-6_tree.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/update-dropdown-options.gif b/17/umbraco-cms/fundamentals/backoffice/images/update-dropdown-options.gif new file mode 100644 index 00000000000..475d8384b68 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/update-dropdown-options.gif differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png new file mode 100644 index 00000000000..dd375cca662 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-01-Content-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png new file mode 100644 index 00000000000..4f038a5eb3f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-02-Actions-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png new file mode 100644 index 00000000000..6a41f9aa5d6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-03-Name-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png new file mode 100644 index 00000000000..f7a15cb548e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-04-Save-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png new file mode 100644 index 00000000000..244f5d796b7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-05-Find-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png new file mode 100644 index 00000000000..5cdb17c7422 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-06-Edit-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png new file mode 100644 index 00000000000..e1f6910d596 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-07-Settings-Menu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png new file mode 100644 index 00000000000..2c610e04b97 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-08-Create-Content-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png new file mode 100644 index 00000000000..ca0480f2704 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-09-Select-Content-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png new file mode 100644 index 00000000000..1d323d33295 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-10-Save-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png new file mode 100644 index 00000000000..a7cde6aabef Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-11-Find-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png new file mode 100644 index 00000000000..3b8be3c5dca Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-12-Create-From-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png b/17/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png new file mode 100644 index 00000000000..251ae8eded3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/v8-13-Select-Template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/varying-content.png b/17/umbraco-cms/fundamentals/backoffice/images/varying-content.png new file mode 100644 index 00000000000..41247e7065e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/varying-content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png b/17/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png new file mode 100644 index 00000000000..79efa211c19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/varying-content_v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/varying-properties.png b/17/umbraco-cms/fundamentals/backoffice/images/varying-properties.png new file mode 100644 index 00000000000..8c01350fe7c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/varying-properties.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png b/17/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png new file mode 100644 index 00000000000..fd949f8dad9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/images/varying-properties_v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/login.md b/17/umbraco-cms/fundamentals/backoffice/login.md new file mode 100644 index 00000000000..ab051c0870e --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/login.md @@ -0,0 +1,280 @@ +--- +description: >- + In this article you can learn the various ways of customizing the Umbraco + backoffice login screen and form. +--- + +# Login + +To access the backoffice, you will need to login. You can do this by adding `/umbraco` at the end of your website URL, for example `http://mywebsite.com/umbraco`. + +You will be presented with a login form similar to this: + +![Login screen](images/login-backoffice-login-v14.png) + +The **login** screen contains a short greeting, a **login form** and an optional **Forgotten password** link. + +Below, you will find instructions on how to customize the login screen. + +## Greeting + +The login screen features a greeting text: The "Welcome" headline. This can be personalized by overriding the existing language translation keys. + +To do this follow the steps below: + +1. Register a 'localization' manifest for the default language of your Umbraco site, (usually en-US) to override the greetings. + +{% code title="App_Plugins/Login/umbraco-package.json" lineNumbers="true" %} +```json +{ + "alias": "login.extensions", + "name": "Login extensions", + "version": "1.0.0", + "allowPublicAccess": true, + "extensions": [ + { + "type": "localization", + "alias": "Login.Localize.EnUS", + "name": "English", + "js": "/App_Plugins/Login/en-us.js", + "meta": { + "culture": "en-US" + } + } + ] +} +``` +{% endcode %} + +2. Add an `en-us.js` file containing the following: + +{% code title="App_Plugins/Login/en-us.js" %} +```javascript +export default { + auth: { + instruction: "Log in again to continue", + greeting0: "Is is Sunday", + greeting1: "Is is Monday", + greeting2: "Is is Tuesday", + greeting3: "Is is Wednesday", + greeting4: "Is is Thursday", + greeting5: "Is is Friday", + greeting6: "Is is Saturday", + } +} +``` +{% endcode %} + +This will override the default greetings with the ones you provide. The login screen will now display "It is Sunday" instead of "Welcome" for example. + +{% hint style="info" %} +The login screen has its own set of localization files independent of the rest of the Backoffice. You can read more about Backoffice localization in the [UI Localization](../../customizing/foundation/localization.md) article. +{% endhint %} + +You can customize other text on the login screen as well. First, grab the default values and keys from the [en.ts](https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Web.UI.Login/src/localization/lang/en.ts) in the Umbraco CMS GitHub repository. Thereafter copy the ones you want to translate into `~/App_Plugins/Login/umbraco-package.json` file. + +## Password reset + +The **Forgotten password?** link allows your backoffice users to reset their password. To use this feature, you will need to add the following key to the `Umbraco.Cms.Security` section in the `appsettings.json` file: + +```json +"Umbraco": { + "CMS": { + "Security": { + "AllowPasswordReset": true + } + } +} +``` + +Set it to `true` to enable the password reset feature, and `false` to disable the feature. + +You will also need to configure a Simple Mail Transfer Protocol (SMTP) server in your `appsettings.json` file. When you get a successful result on the SMTP configuration when running a health check in the backoffice, you are good to go! + +An example: + +```json +"Umbraco": { + "CMS": { + "Global": { + "Id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "Smtp": { + "From": "noreply@test.com", + "Host": "127.0.0.1", + "Username": "username", + "Password": "password" + } + } + } +} +``` + +## Custom background image and logo + +It is possible to customize the background image and the logo for the backoffice login screen by adding the `"Content"` section in the `appsettings.json` file: + +```json +"Umbraco": { + "CMS": { + "Content": { + "LoginBackgroundImage": "../myImagesFolder/myLogin.jpg", + "LoginLogoImage": "../myImagesFolder/myLogo.svg", + "LoginLogoImageAlternative": "../myImagesFolder/myLogo.svg" + } + } +} +``` + +The `LoginBackgroundImage`, `LoginLogoImage`, and `LoginLogoImageAlternative` are referenced from the `/wwwroot/umbraco/` folder. + +The `LoginLogoImage` is displayed on top of the `LoginBackgroundImage` and the `LoginLogoImageAlternative` is displayed when the `LoginLogoImage` is not available, for example on small resolutions. + +## Custom CSS + +You can also customize the login screen by adding a custom CSS file. To do this, you will need to add a new file inside the `~/App_Plugins` folder, for example `~/App_Plugins/Login/my-custom-login-screen.css`. + +You can then add your custom CSS to the file: + +```css +:root { + --umb-login-curves-color: rgba(0, 0, 0, 0.1); +} +``` + +This will change the color of the SVG graphics (curves) shown on the login screen. You can also hide the curves by adding the following CSS: + +```css +:root { + --umb-login-curves-display: none; +} +``` + +### Load the custom CSS file + +To tell Umbraco about your custom CSS file, you will need to add a `umbraco-package.json` file. The `umbraco-package.json` file should look like this: + +```json +{ + "alias": "login.extensions", + "name": "Login extensions", + "version": "1.0.0", + "allowPublicAccess": true, + "extensions": [ + { + "type": "appEntryPoint", + "alias": "MyCustomLoginScreen", + "name": "My Custom Login Screen", + "js": "/App_Plugins/Login/my-custom-login-screen.js" + } + ] +} +``` + +Next add a JavaScript file, for example `~/App_Plugins/Login/my-custom-login-screen.js`, and add the following code to load the custom CSS file: + +```javascript +const link = document.createElement('link'); +link.rel = 'stylesheet'; +link.href = '/App_Plugins/Login/my-custom-login-screen.css'; +document.head.appendChild(link); +``` + +This will load the custom CSS file into Umbraco. + +{% hint style="warning" %} +Be aware that the custom CSS file will be loaded on all Umbraco screens, not only the login screen. +{% endhint %} + +### Custom CSS properties reference + +The following CSS properties are available for customization: + +| CSS Property | Description | Default Value | +| ---------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------ | +| `--umb-login-background` | The background of the layout | `#f4f4f4` | +| `--umb-login-primary-color` | The color of the headline | `#283a97` | +| `--umb-login-text-color` | The color of the text | `#000` | +| `--umb-login-header-font-size` | The font-size of the headline | `3rem` | +| `--umb-login-header-font-size-large` | The font-size of the headline on large screens | `4rem` | +| `--umb-login-header-secondary-font-size` | The font-size of the secondary headline | `2.4rem` | +| `--umb-login-image` | The background of the image wrapper | The value of the [LoginBackgroundImage](login.md#custom-background-image-and-logo) setting | +| `--umb-login-image-display` | The display of the image wrapper | `flex` | +| `--umb-login-image-border-radius` | The border-radius of the image wrapper | `38px` | +| `--umb-login-content-background` | The background of the content wrapper | `none` | +| `--umb-login-content-display` | The display of the content wrapper | `flex` | +| `--umb-login-content-width` | The width of the content wrapper | `100%` | +| `--umb-login-content-height` | The height of the content wrapper | `100%` | +| `--umb-login-content-border-radius` | The border-radius of the content wrapper | `0` | +| `--umb-login-align-items` | The align-items of the main wrapper | `unset` | +| `--umb-login-button-border-radius` | The border-radius of the buttons | `45px` | +| `--umb-login-curves-color` | The color of the curves | `#f5c1bc` | +| `--umb-login-curves-display` | The display of the curves | `inline` | + +The CSS custom properties may change in future versions of Umbraco. You can always find the latest values in the [login layout element](https://github.com/umbraco/Umbraco-CMS/blob/v14/dev/src/Umbraco.Web.UI.Login/src/components/layouts/auth-layout.element.ts) in the Umbraco CMS GitHub repository. + +## The Time Out Screen + +![Time out screen](images/timeout-screen.jpg) + +The time out screen is displayed when the user has been inactive for a certain amount of time. The screen resembles the login screen in many ways and the two are sometimes confused. The most notable difference is that the time out screen does not have a login form. It only has a message and a button to log in again with Umbraco. + +If you have added more than one login provider, the users will also see this screen first. This is because they need to choose which provider to use first. In that case, the screen is also referred to as the **Choose provider screen**. + +You can customize the time out screen in the same way as the login screen. The time out screen uses the same localization files as the rest of the Backoffice and **not** those of the login screen. The notable difference is that the time out screen is scoped to the `login` section. The login screen is scoped to the `auth` section of the localization files. + +### Greeting + +To update the greeting message on this screen, you will have to change the section to `login`: + +{% code title="App_Plugins/Login/umbraco-package.json" lineNumbers="true" %} +```json +{ + "alias": "login.extensions", + "name": "Login extensions", + "version": "1.0.0", + "allowPublicAccess": true, + "extensions": [ + { + "type": "localization", + "alias": "Login.Localize.EnUS", + "name": "English", + "js": "/App_Plugins/Login/en-us.js", + "meta": { + "culture": "en-US" + } + } + ] +} +``` +{% endcode %} + +The `en-us.js` file should contain the following: + +{% code title="App_Plugins/Login/en-us.js" %} +```javascript +export default { + auth: { + instruction: "Log in again to continue", + greeting0: "Is is Sunday", + greeting1: "Is is Monday", + greeting2: "Is is Tuesday", + greeting3: "Is is Wednesday", + greeting4: "Is is Thursday", + greeting5: "Is is Friday", + greeting6: "Is is Saturday", + } +} +``` +{% endcode %} + +The `instruction` key is shown when the user has timed out, and the `greeting0..6` keys are shown when the user has to choose a login provider. + +### Image + +You can update the image on the time out screen through a custom CSS variable. The default value is `--umb-login-image` and it is set to the same value as the login screen. You can override this value in your custom CSS file: + +```css +:root { + --umb-login-image: url(../myImagesFolder/myTimeout.jpg); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/logviewer.md b/17/umbraco-cms/fundamentals/backoffice/logviewer.md new file mode 100644 index 00000000000..d959abf7b0c --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/logviewer.md @@ -0,0 +1,231 @@ +--- +description: Information on using the Umbraco log viewer +--- + +# Log Viewer + +Umbraco ships with a built-in Log Viewer feature. This allows you to filter, view log entries, perform complex search queries, and analyze logs for debugging. You can find the Log viewer in the **Settings** section of the Umbraco backoffice. + +{% embed url="https://youtu.be/PDqIRVygAQ4?t=102" %} +Learn how to use the Log Viewer to read and understand logs for your Umbraco CMS website. +{% endembed %} + +## Benefits + +Ever needed to find all log entries containing the same request ID? Or locate all logs where a property called `Duration` exceeds 1000ms? + +With structured logging and a query language, you can efficiently search and identify log items for specific scenarios. This helps in debugging and finding patterns in your logs, making it easier to resolve issues. + +## Example Queries + +Here are some example queries to help you get started. For more details on the syntax, see the https://github.com/serilog/serilog-filters-expressions project. + +**Find all logs that are from the namespace 'Umbraco.Core'**`StartsWith(SourceContext, 'Umbraco.Core')` + +**Find all logs that have the property 'Duration' and the duration is greater than 1000ms**`Has(Duration) and Duration > 1000` + +**Find all logs where the message has localhost in it with SQL like**`@Message like '%localhost%'` + +## Saved Searches + +If you frequently use a custom query, you can save it for quick access. Type your query in the search box and click the heart icon to save it with a friendly name. Saved queries are stored in the `umbracoLogViewerQuery` table in the database. + +## Implementing Your Own Log Viewer Source + +Umbraco allows you to implement a custom `ILogViewerRepository` and `ILogViewerService` to fetch logs from alternative sources, such as **Azure Table Storage**. + +### Creating a Custom Log Viewer Repository + +To fetch logs from Azure Table Storage, extend the `LogViewerRepositoryBase` class from `Umbraco.Cms.Infrastructure.Services.Implement`. + +{% hint style="info" %} +This implementation requires the `Azure.Data.Tables` NuGet package. +{% endhint %} + +```csharp +using Azure; +using Azure.Data.Tables; +using Serilog.Events; +using Serilog.Formatting.Compact.Reader; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Logging.Viewer; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Logging.Serilog; +using Umbraco.Cms.Infrastructure.Services.Implement; + +namespace My.Website; + +public class AzureTableLogsRepository : LogViewerRepositoryBase +{ + private readonly IJsonSerializer _jsonSerializer; + + public AzureTableLogsRepository(UmbracoFileConfiguration umbracoFileConfig, IJsonSerializer jsonSerializer) : base( + umbracoFileConfig) + { + _jsonSerializer = jsonSerializer; + } + + protected override IEnumerable GetLogs(LogTimePeriod logTimePeriod, ILogFilter logFilter) + { + // This example uses a connection string compatible with the Azurite emulator + // https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite + var client = + new TableClient( + "UseDevelopmentStorage=true", + "LogEventEntity"); + + // Filter by timestamp to avoid retrieving all logs from the table, preventing memory and performance issues + IEnumerable results = client.Query( + entity => entity.Timestamp >= logTimePeriod.StartTime.Date && + entity.Timestamp <= logTimePeriod.EndTime.Date.AddDays(1).AddSeconds(-1)); + + // Read the data and apply logfilters + IEnumerable filteredData = results.Select(x => LogEventReader.ReadFromString(x.Data)) + .Where(logFilter.TakeLogEvent); + + return filteredData.Select(x => new LogEntry + { + Timestamp = x.Timestamp, + Level = Enum.Parse(x.Level.ToString()), + MessageTemplateText = x.MessageTemplate.Text, + Exception = x.Exception?.ToString(), + Properties = MapLogMessageProperties(x.Properties), + RenderedMessage = x.RenderMessage(), + }); + } + + private IReadOnlyDictionary MapLogMessageProperties( + IReadOnlyDictionary? properties) + { + var result = new Dictionary(); + + if (properties is not null) + { + foreach (KeyValuePair property in properties) + { + string? value; + + if (property.Value is ScalarValue scalarValue) + { + value = scalarValue.Value?.ToString(); + } + else if (property.Value is StructureValue structureValue) + { + var textWriter = new StringWriter(); + structureValue.Render(textWriter); + value = textWriter.ToString(); + } + else + { + value = _jsonSerializer.Serialize(property.Value); + } + + result.Add(property.Key, value); + } + } + + return result; + } + + public class AzureTableLogEntity : ITableEntity + { + public required string Data { get; set; } + + public required string PartitionKey { get; set; } + + public required string RowKey { get; set; } + + public DateTimeOffset? Timestamp { get; set; } + + public ETag ETag { get; set; } + } +} +``` + +Azure Table Storage requires entities to implement the `ITableEntity` interface. Since Umbraco's default log entity does not implement this, a custom entity (`AzureTableLogEntity`) must be created to ensure logs are correctly fetched. + +### Creating a custom log viewer service + +The next thing to do is create a new implementation of `ILogViewerService`. Amongst other things, this is responsible for figuring out whether a provided log query is allowed. Again a base class is available. + +```csharp +public class AzureTableLogsService : LogViewerServiceBase +{ + public AzureTableLogsService( + ILogViewerQueryRepository logViewerQueryRepository, + ICoreScopeProvider provider, + ILogViewerRepository logViewerRepository) + : base(logViewerQueryRepository, provider, logViewerRepository) + { + } + + // Change this to what you think is sensible. + // As an example, check whether more than 5 days off logs are requested. + public override Task> CanViewLogsAsync(LogTimePeriod logTimePeriod) + { + return logTimePeriod.EndTime - logTimePeriod.StartTime < TimeSpan.FromDays(5) + ? Task.FromResult(Attempt.SucceedWithStatus(LogViewerOperationStatus.Success, true)) + : Task.FromResult(Attempt.FailWithStatus(LogViewerOperationStatus.CancelledByLogsSizeValidation, false)); + } + + public override ReadOnlyDictionary GetLogLevelsFromSinks() + { + var configuredLogLevels = new Dictionary + { + { "Global", GetGlobalMinLogLevel() }, + { "AzureTableStorage", LogViewerRepository.RestrictedToMinimumLevel() }, + }; + + return configuredLogLevels.AsReadOnly(); + } +} +``` + +### Register implementations + +Umbraco needs to be made aware that there is a new implementation of an `ILogViewerRepository` and an `ILogViewerService`. These need to replace the default ones that are shipped with Umbraco. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Infrastructure.DependencyInjection; +using Umbraco.Cms.Core.Services; + +namespace My.Website; + +public class AzureTableLogsComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.Services.AddUnique(); + } + } +} +``` + +### Configuring Logging to Azure Table Storage + +With the above three classes, the setup is in place to view logs from an Azure Table. However, logs are not yet persisted into the Azure Table Storage account. To enable persistence, configure the Serilog logging pipeline to store logs in Azure Table Storage. + +- Install `Serilog.Sinks.AzureTableStorage` from NuGet. +- Add a new sink to `appsettings.json` with credentials to persist logs to Azure. + +The following sink needs to be added to the [`Serilog:WriteTo`](https://github.com/serilog/serilog-sinks-azuretablestorage#json-configuration) array. + +```json +{ + "Name": "AzureTableStorage", + "Args": { + "storageTableName": "LogEventEntity", + "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact", + "connectionString": "DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=KEY;EndpointSuffix=core.windows.net" + } +} +``` + +For more in-depth information about logging and how to configure it, see the [Logging](../code/debugging/logging.md) article. + +### Compact Log Viewer - Desktop App + +[Compact Log Viewer](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge&ocid=badge). A desktop tool is available for viewing and querying JSON log files in the same way as the built-in Log Viewer in Umbraco. diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/README.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/README.md new file mode 100644 index 00000000000..14ef02e86d8 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/README.md @@ -0,0 +1,36 @@ +--- +description: >- + Learn more about the default property editors that ships with an Umbraco + installation. +--- + +# Property Editors + +A Property Editor is the editor that a Data Type references. A Data Type is defined by a user in the Umbraco backoffice and references a Property Editor. In Umbraco a Property Editor is defined in a JSON manifest file and associated JavaScript files. + +{% hint style="info" %} +**Are you looking for the Grid Layout or Nested Content?** + +The following Property Editors have been removed with the release of Umbraco 14: + +* Grid Layout +* Nested content + +We recommend using the [Block Editor](built-in-umbraco-property-editors/block-editor/) or the [Rich Text Editor Blocks](broken-reference) instead. +{% endhint %} + +When creating a Data Type, specify the property editor for the Data Type to use by selecting from the "Property editor" list (as shown below). + +![Data Type Definition](../../../../../14/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Media-picker-dataType.png) + +## [Built-in Property Editors in Umbraco](built-in-umbraco-property-editors/) + +Umbraco comes pre-installed with many useful property editors. + +## More information + +* [Customizing Data Types](../../data/data-types/) + +## Tutorials + +* [How to create a custom Property Editor](../../../tutorials/creating-a-property-editor/) diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png new file mode 100644 index 00000000000..b77fcfc1257 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png new file mode 100644 index 00000000000..644ec9d1b1a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png new file mode 100644 index 00000000000..ae25f727ec1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png new file mode 100644 index 00000000000..27a9a510790 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png new file mode 100644 index 00000000000..b519f0b755b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png new file mode 100644 index 00000000000..826d46925e4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png new file mode 100644 index 00000000000..fe5fec9d0df Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png new file mode 100644 index 00000000000..5509be958d5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png new file mode 100644 index 00000000000..aee9a56f88a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png new file mode 100644 index 00000000000..aeb71eb6354 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg new file mode 100644 index 00000000000..8b20c59740b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg new file mode 100644 index 00000000000..48ca8012ceb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg new file mode 100644 index 00000000000..265f40b2b50 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg new file mode 100644 index 00000000000..d55344cfab6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png new file mode 100644 index 00000000000..55f022f185c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg new file mode 100644 index 00000000000..06e3952f0d6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg new file mode 100644 index 00000000000..0bc57cb6dcb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png new file mode 100644 index 00000000000..3c461f50f2a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Install-Sample-Configuration.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif new file mode 100644 index 00000000000..3cd187ba55c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Resizing-Blocks.gif differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif new file mode 100644 index 00000000000..b5a762aad5d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif new file mode 100644 index 00000000000..f56d714d12b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/resizing-block-block-grid.gif differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png new file mode 100644 index 00000000000..51a442213de Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png new file mode 100644 index 00000000000..0ea95d1f653 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png new file mode 100644 index 00000000000..da2e4783a21 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png new file mode 100644 index 00000000000..748994a5133 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png new file mode 100644 index 00000000000..4c3e82f6475 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png new file mode 100644 index 00000000000..9f32f5a1403 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png new file mode 100644 index 00000000000..ffcdc6226ed Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/Dropdown-List-Keys-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png new file mode 100644 index 00000000000..9d2fd30a993 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png new file mode 100644 index 00000000000..be48cc06e30 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png new file mode 100644 index 00000000000..b1a7bebeeee Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-config.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg new file mode 100644 index 00000000000..1a1669ea764 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-configuration.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg new file mode 100644 index 00000000000..6f2ee70af01 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-NO-SIDEBAR-rows.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg new file mode 100644 index 00000000000..82c269292fa Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-rows.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg new file mode 100644 index 00000000000..68e9eaa12b6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios-1.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg new file mode 100644 index 00000000000..89c46c8e2a6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout-scenarios.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg new file mode 100644 index 00000000000..c568c3bc883 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/Grid-layout.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png new file mode 100644 index 00000000000..7a08e22f31e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/cells.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png new file mode 100644 index 00000000000..f2cabc6bd80 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/editor.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png new file mode 100644 index 00000000000..43795bb6e72 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-resizing.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png new file mode 100644 index 00000000000..be277afce13 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-settings-and-style.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg new file mode 100644 index 00000000000..743294e00e0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/grid-wireframe.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png new file mode 100644 index 00000000000..1d56b4e1077 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layout.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png new file mode 100644 index 00000000000..92d35914331 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/layouts.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png new file mode 100644 index 00000000000..324ada87d38 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/rows.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png new file mode 100644 index 00000000000..5cbec50a771 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/grid-layout/Images/settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png new file mode 100644 index 00000000000..317fcc0be6f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Bulk-action.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png new file mode 100644 index 00000000000..816cd894624 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png new file mode 100644 index 00000000000..3f1b3f5769d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png new file mode 100644 index 00000000000..b5c12f01a4f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Data-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png new file mode 100644 index 00000000000..1bf70361a19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png new file mode 100644 index 00000000000..afa79301ebb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png new file mode 100644 index 00000000000..192d2d14d6a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png new file mode 100644 index 00000000000..dce3cfb3707 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png new file mode 100644 index 00000000000..cdb0b000552 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png new file mode 100644 index 00000000000..7a5462d5c5f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png new file mode 100644 index 00000000000..e6501f8493b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png new file mode 100644 index 00000000000..c8f7c80d8db Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png new file mode 100644 index 00000000000..19ee214659f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-8_1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png new file mode 100644 index 00000000000..b3fc75721fc Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png new file mode 100644 index 00000000000..9961538e7b7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png new file mode 100644 index 00000000000..305193e35a5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png new file mode 100644 index 00000000000..7785bfc843a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png new file mode 100644 index 00000000000..0488e5ca139 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker2-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png new file mode 100644 index 00000000000..e24f72dc290 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-app-icon.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png new file mode 100644 index 00000000000..ad132be4a7f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Csv-example-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png new file mode 100644 index 00000000000..1ebdd54aaaa Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png new file mode 100644 index 00000000000..2460047b337 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png new file mode 100644 index 00000000000..1b1573f3cdc Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-With-Time-Data-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png new file mode 100644 index 00000000000..c0c5dfb8d60 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png new file mode 100644 index 00000000000..71b57446e23 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png new file mode 100644 index 00000000000..4d69318f166 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png new file mode 100644 index 00000000000..8a23ef3e7dd Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png new file mode 100644 index 00000000000..fe097a4cfab Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-DataType-v88.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png new file mode 100644 index 00000000000..d404b98533b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png new file mode 100644 index 00000000000..c8d568092ed Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Eye-Dropper-Color-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png new file mode 100644 index 00000000000..83a6fc3ac28 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png new file mode 100644 index 00000000000..509f6bc80d8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Json-example-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png new file mode 100644 index 00000000000..8542a32ceb9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png new file mode 100644 index 00000000000..c3c57f0a063 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Setup-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png new file mode 100644 index 00000000000..e71cbb2825f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png new file mode 100644 index 00000000000..d697795c88a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-definition-example-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png new file mode 100644 index 00000000000..22adeb1cfed Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg new file mode 100644 index 00000000000..ab98dd1c544 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-Content.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png new file mode 100644 index 00000000000..06b96e1f7aa Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-8_1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png new file mode 100644 index 00000000000..761f85d1b08 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png new file mode 100644 index 00000000000..47a81f806f8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg new file mode 100644 index 00000000000..9ac41a5e833 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker-DataType.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png new file mode 100644 index 00000000000..d608e07bddc Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png new file mode 100644 index 00000000000..aebba80af59 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker2-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg new file mode 100644 index 00000000000..4cf7c146c4a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg new file mode 100644 index 00000000000..5bd2ba0f4fa Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-DataType.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png new file mode 100644 index 00000000000..a779088cce0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/MediaPicker-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png new file mode 100644 index 00000000000..33109a95d23 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png new file mode 100644 index 00000000000..5f01d0e0fac Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png new file mode 100644 index 00000000000..7b192ab851c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png new file mode 100644 index 00000000000..e1b845db8e7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png new file mode 100644 index 00000000000..b62615b15de Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png new file mode 100644 index 00000000000..83e70feba90 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg new file mode 100644 index 00000000000..1f59bd1aa4e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-Content.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png new file mode 100644 index 00000000000..a5b012f17c6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-8_1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png new file mode 100644 index 00000000000..373a1683542 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png new file mode 100644 index 00000000000..824437a853c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg new file mode 100644 index 00000000000..bb3ab928c11 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-Content.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png new file mode 100644 index 00000000000..f6ce9d537f1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multinode-Treepicker2-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (2).png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1).png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (2).png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png new file mode 100644 index 00000000000..ce2969ab86c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png new file mode 100644 index 00000000000..3e2453ac34e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-8_1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png new file mode 100644 index 00000000000..062da5499b4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png new file mode 100644 index 00000000000..4f9616254e2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png new file mode 100644 index 00000000000..98414978dc3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_AddContent.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png new file mode 100644 index 00000000000..161b7936661 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png new file mode 100644 index 00000000000..dda7d36f1eb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_DataTypeDefinition.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png new file mode 100644 index 00000000000..94c5c38a18e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png new file mode 100644 index 00000000000..da6b1155c87 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_EditItem.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png new file mode 100644 index 00000000000..f762ddad70b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png new file mode 100644 index 00000000000..fcde18e4093 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NewItem.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png new file mode 100644 index 00000000000..0c6117c24cd Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_NotSupported.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png new file mode 100644 index 00000000000..d1ce4c68a49 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png new file mode 100644 index 00000000000..08e3d50241a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SelectSchema.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png new file mode 100644 index 00000000000..7ca1a2aa5cd Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png new file mode 100644 index 00000000000..f0339bd55c7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/NestedContent_SingleItemMode.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png new file mode 100644 index 00000000000..1b127cb708f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v7.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png new file mode 100644 index 00000000000..dffc9993677 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png new file mode 100644 index 00000000000..2127a4f1ced Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png new file mode 100644 index 00000000000..142fa243b8b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v7.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png new file mode 100644 index 00000000000..8ba95eb0960 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg new file mode 100644 index 00000000000..69a93e1b650 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-Content.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg new file mode 100644 index 00000000000..ed7f4b3cd0f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links-DataType.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png new file mode 100644 index 00000000000..2a794696fc7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png new file mode 100644 index 00000000000..7dff6a53a7a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Related-Links2-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png new file mode 100644 index 00000000000..7c3e61eae19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png new file mode 100644 index 00000000000..9712de40e4b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png new file mode 100644 index 00000000000..4111a53f682 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Repeatable-Textstrings-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png new file mode 100644 index 00000000000..94a6744a65d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-With-Range.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG new file mode 100644 index 00000000000..defbec9d5c0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Content-Example-no-range.PNG differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png new file mode 100644 index 00000000000..83075cd06e3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Slider-Data-Type-Definition-Example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png new file mode 100644 index 00000000000..28df576cc66 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png new file mode 100644 index 00000000000..4cdceafb098 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Tags-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png new file mode 100644 index 00000000000..11b0429ae07 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png new file mode 100644 index 00000000000..a705fe2e373 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png new file mode 100644 index 00000000000..10056565a9e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-Limit-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png new file mode 100644 index 00000000000..c9fc0f6ab18 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png new file mode 100644 index 00000000000..57e204be5da Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Setup-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png new file mode 100644 index 00000000000..3fac1920ccf Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png new file mode 100644 index 00000000000..0d11476b79d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png new file mode 100644 index 00000000000..63c007e993b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png new file mode 100644 index 00000000000..6be488e2c47 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Setup-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png new file mode 100644 index 00000000000..f9e2ee1d4f9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg new file mode 100644 index 00000000000..3fed90221c1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/True-False-DataType-742.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png new file mode 100644 index 00000000000..36c7d8ab560 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Typeahead-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png new file mode 100644 index 00000000000..b10862a78f2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png new file mode 100644 index 00000000000..e2e6107c9e6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-DataType-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png new file mode 100644 index 00000000000..091b76744a6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png new file mode 100644 index 00000000000..31e261468bb Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png new file mode 100644 index 00000000000..cbc8b32dab8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-setup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png new file mode 100644 index 00000000000..7fed23ebeaf Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/configuration.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png new file mode 100644 index 00000000000..c52090520a5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png new file mode 100644 index 00000000000..43de1d23057 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png new file mode 100644 index 00000000000..9eab72c6175 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/crop.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png new file mode 100644 index 00000000000..679cf442191 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/datatype.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png new file mode 100644 index 00000000000..af4255a5566 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-picker-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png new file mode 100644 index 00000000000..04e52f6da2c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/date-time-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png new file mode 100644 index 00000000000..64f63e9d0d3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png new file mode 100644 index 00000000000..16ad8acfcd0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/definition-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png new file mode 100644 index 00000000000..d89366ff495 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/emailaddress-datatype-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png new file mode 100644 index 00000000000..1bd0f06ee35 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/enable-listview.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png new file mode 100644 index 00000000000..e315b62e092 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/focalpoint.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png new file mode 100644 index 00000000000..fbbb3983ca0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-crop-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png new file mode 100644 index 00000000000..6d7faf59490 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-focalpoint-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png new file mode 100644 index 00000000000..94e5f4e3056 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png new file mode 100644 index 00000000000..71285c8067a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v8.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png new file mode 100644 index 00000000000..18bddd8e816 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-v9.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png new file mode 100644 index 00000000000..e9ed8be01f5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png new file mode 100644 index 00000000000..303197e4571 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-member-picked.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png new file mode 100644 index 00000000000..779fee60cd3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings1-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png new file mode 100644 index 00000000000..ddb8b025c09 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-view-settings2-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png new file mode 100644 index 00000000000..4224ff7dcad Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png new file mode 100644 index 00000000000..b20a1a15a63 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-content-example-email.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png new file mode 100644 index 00000000000..55783a6a881 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property-dropdown.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png new file mode 100644 index 00000000000..6d8cc9b007a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-property.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png new file mode 100644 index 00000000000..3f79b7b6af9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings-2.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png new file mode 100644 index 00000000000..c34dd7dd17b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png new file mode 100644 index 00000000000..6e6495012ec Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/listview.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png new file mode 100644 index 00000000000..72956366eb8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/mandatory-checkbox.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png new file mode 100644 index 00000000000..888e6eeb6ee Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png new file mode 100644 index 00000000000..a750e3f6ab5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/member-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png new file mode 100644 index 00000000000..165126a8334 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png new file mode 100644 index 00000000000..80cab7f01f1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype-v10.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png new file mode 100644 index 00000000000..cca349097c3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-datatype.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png new file mode 100644 index 00000000000..d9ca0303dc3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others-result.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png new file mode 100644 index 00000000000..29780fc0632 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/others.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png new file mode 100644 index 00000000000..e7ebbae510e Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/picked-member.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png new file mode 100644 index 00000000000..2d0bddbf0c7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/upload.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png new file mode 100644 index 00000000000..0665c1c1b87 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/wip.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md new file mode 100644 index 00000000000..59ba7b8ffe7 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/README.md @@ -0,0 +1,2 @@ +# Built-in Property Editors + diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md new file mode 100644 index 00000000000..bf1f3ed396e --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md @@ -0,0 +1,19 @@ +# Block Editors + +The Block Editors are property editors that enabled you to build advanced editor tools using a set of predefined Document Types. + +{% hint style="warning" %} +This article is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Umbraco CMS currently ships with two Block Editors: the Block List and the Block Grid. + +## [Block List](block-list-editor.md) + +## [Block Grid](block-grid-editor.md) + +## Customizing Block Editors + +### [Creating custom views for blocks](../../../../../tutorials/creating-custom-views-for-blocklist.md) + +Learn how to create custom views for the blocks used in your Block Grid or Block List property editors. diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md new file mode 100644 index 00000000000..468a2b4414a --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md @@ -0,0 +1,737 @@ +# Block Grid + +`Schema Alias: Umbraco.BlockGrid` + +`UI Alias: Umb.PropertyEditorUi.BlockGrid` + +`Returns: BlockGridModel` + +The **Block Grid** property editor enables editors to layout their content in the Umbraco backoffice. The content is made of Blocks that can contain different types of data. + +{% hint style="warning" %} +This article is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +## Sample configuration + +When testing out the property editor, you can use a set of predefined Blocks. The option will only be possible when there are no other Data Types using the Block Grid property editor. + +
+ +* Create a new **Data Type**. +* Select the **Block Grid** as the **Property editor**. +* **Install** the "Sample Configuration". + +4 Blocks will be added to the property, ready for testing. + +## Configuring the Block Grid + +The Block Grid property editor is configured via the **Data Types** backoffice interface. + +To set up the Block Grid property editor, follow these steps: + +1. Navigate to the **Settings** section in the Umbraco backoffice. +2. Click **...** next to the **Data Types** folder. +3. Select **Create** -> **New Data Type**. +4. Select **Block Grid** from the list of available property editors. + +You will see the configuration options for a Block Grid property editor as shown below: + +![Block Grid - Data Type Configuration](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png) + +The Data Type editor allows you to configure the following properties: + +* **Blocks** - Defines the Block Types available for use in the property. For more information, see [Setup Block Types](block-grid-editor.md#setup-block-types). +* **Amount** - Sets the minimum and/or the maximum number of Blocks that should be allowed at the root of the layout. +* **Live editing mode** - Enabling this option will allow you to see the changes as you are editing them. +* **Editor width** - Overwrites the width of the property editor. This field takes any valid CSS value for "max-width". For example: 100% or 800px. +* **Grid Columns** - Define the number of columns in your Block Grid. The default is 12 columns. +* **Layout Stylesheet** - Replaces the built-in Layout Stylesheet. Additionally, you can retrieve the default layout stylesheet to use as a base for your own inspiration or for writing your own stylesheet. +* **Create Button Label** - Overwrites the label on the Create button. + +## Setup Block Types + +Block Types are based on [**Element Types**](../../../../data/defining-content/#element-types). These can be created beforehand or while setting up your Block Types. + +Once you have added an Element Type as a Block Type on your Block Grid Data Type you have the option to configure it. + +![Block Grid - Data Type Block Configuration](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png) + +### Groups + +Blocks can also be grouped. This is visible in the Block Catalogue and can also be used to allow a group of Blocks in an Area. + +## Block Configuration Settings + +Each Block has a set of properties that are optional to configure. These are described below. + +### General + +Customize the user experience for your content editors when they work with the Blocks in the Content section. + +* **Label** - Defines a label for the appearance of the Block in the editor. The label can use AngularJS template-string-syntax to display values of properties. The label is also used for search in the **Add Block** dialog during content editing. If no label is defined, the block will not be searchable. The search does not fall back to the block’s name. + +{% hint style="info" %} +Label example: "My Block {=myPropertyAlias}" will be shown as: "My Block FooBar". +{% endhint %} + +* **Content model** - Presents the Element Type used as model for the Content section of this Block. This cannot be changed but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label. +* **Settings model** - Adds a Settings section to your Block based on a given Element Type. When selected you can open the Element Type or choose to remove the Settings section again. + +### Size options + +Customize the Blocks size in the Grid. If you define multiple options, the Block becomes scalable. + +By default, a Block takes up the available width. + +A Block can be resized in two ways: + +1. When a Block is placed in an Area, it will fit to the Areas width. Learn more about [Areas](block-grid-editor.md#areas). +2. A Block can have one or more Column Span options defined. + +A Column Span option is used to define the width of a Block. With multiple Column Span options defined, the Content Editor can scale the Block to fit specific needs. + +Additionally, Blocks can be configured to span rows, this enables one Block to be placed next to a few rows containing other Blocks. + +* **Available column spans** - Defines one or more columns, the Block spans across. For example: in a 12 columns grid, 6 columns is equivalent to half width. By enabling 6 columns and 12 columns, the Block can be scaled to either half width or full width. +* **Available row spans** - Defines the amount of rows the Block spans across. + +See the [scaling blocks](block-grid-editor.md#scaling-blocks) section of this article for an example of how scaling works. + +### Catalogue appearance + +These properties refer to how the Block is presented in the Block catalogue when editors choose which Blocks to use for their content. + +* **Background color** - Defines a background color to be displayed beneath the icon or thumbnail. Example: `#424242`. +* **Icon color** - Changes the color of the Element Type icon. Example: `#242424`. +* **Thumbnail** - Pick an image or Scalable Vector Graphics (SVG) file to replace the icon of the Block in the catalogue. + +The thumbnails for the catalogue are presented in the format of 16:10. We recommend a resolution of 400px width and 250px height. + +### Permissions + +* **Allow in root** - Determines whether the Block can be created at the root of your layout. Turn this off if you only want a Block to appear within Block Areas. +* **Allow in areas** - Determines whether the Block can be created inside Areas of other Blocks. If this is turned off it can still be allowed in Block Areas by defining specific allowed Blocks. + +## Areas + +Blocks can nest other Blocks to support specific compositions. These compositions can be used as a layout for other Blocks. + +To achieve nesting, a Block must have one or more Areas defined. Each Area can contain one or more Blocks. + +Each Area has a size, defined by column and rows spans. The grid for the Areas are based on the same amount of columns as your root grid, unless you choose to change it. + +To scale an Area, click and drag the scale-button in the bottom-right corner of an Area. + +* **Grid Columns for Areas** - Overwrites the amount of columns used for the Area grid. +* **Areas** - Determines whether the Block can be created inside Areas of other Blocks. + +![Block Grid - Areas](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png) + +### Area configuration + +![Block Grid - Area Configuration](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png) + +* **Alias** - The alias is used to identify this Area. It is being printed by `GetBlockGridHTML()` and used as name for the Area slot in Custom Views. The alias is also available for CSS Selectors to target the HTML-Element representing an Area. +* **Create Button Label** - Overwrites the Create Button Label of the Area. +* **Number of blocks** - Determines the total number of Blocks in an Area. +* **Allowed block types** - When this is empty, all Blocks with Permissions for creation in Areas, will be available. This can be overwritten by specifying the allowed Blocks. Define the types of Blocks or Groups of Blocks that are allowed. Additionally, you can also set how many Blocks of each type/group should be present. + +When allowing a Group of Blocks, you might want to require a specific amount for a certain Block of that Group. This can be done by adding that Block Type to the list as well and set the requirements. + +## Advanced + +These properties are relevant when working with custom views or complex projects. + +* **Custom view** - Overwrites the AngularJS view for the block presentation in the Content editor. Use this view to make a more visual presentation of the Block or make your own editing experience by adding your own AngularJS controller to the view. + +{% hint style="info" %} +Notice that any styling of a Block is scoped. This means that the default backoffice styles are not present for the view of this Block. +{% endhint %} + +* **Custom stylesheet** - Pick your own stylesheet to be used by the Block in the Content editor. +* **Overlay editor size** - Sets the size for the Content editor overlay for editing this block. +* **Hide content editor** - Hides the UI for editing the content in a Block Editor. This is only relevant if you made a custom view that provides the UI for editing of content. + +## Editing Blocks + +When viewing a **Block Grid** property editor in the **Content** section for the first time, you will be presented with the option to **Add content**. + +![Block Grid - Add Content](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png) + +Clicking the **Add content** button opens up the **Block Catalogue**. + +![Block Grid - Setup](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png) + +The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance. + +![Block Grid - example setup](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png) + +Click the Block Type you wish to create and a new Block will appear in the layout. + +More Blocks can be added to the layout by clicking the Add content button. Alternatively, use the Add content button that appears on hover to add new Blocks between, besides, or above the existing Blocks. + +![Block Grid - Add Content Inline](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png) + +To delete a Block, click the trash icon which appears on the mouse hover. + +![Block Grid - Delete Content](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png) + +## Sorting Blocks + +Blocks can be rearranged using the click and drag feature. Move them up or down to place them in the desired order. + +Moving a Block from one Area to another is done in the same way. If a Block is not allowed in the given position, the area will display a red color and not allow the new position. + +![Block Grid - Sorting Blocks](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif) + +## Scaling Blocks + +If a Block has multiple size options it can be scaled via the UI. This appears in the bottom left corner of the Block. + +The Block is resized using a click-and-drag feature. Moving the mouse will change the size to the size options closest to the mouse pointer. + +

Scale blocks in the grid by dragging from the bottom-right corner.

+ +## Rendering Block Grid Content + +Rendering the stored value of your **Block Grid** property editor can be done in two ways: + +1. [Default rendering](block-grid-editor.md#1-default-rendering) +2. [Build your own rendering](block-grid-editor.md#2-build-your-own-rendering) + +### 1. Default rendering + +You can choose to use the built-in rendering mechanism for rendering Blocks using a Partial View for each block. + +The default rendering method is named `GetBlockGridHtmlAsync()` and comes with a few options - for example: + +```csharp +@await Html.GetBlockGridHtmlAsync(Model, "myGrid") +``` + +In the sample above `"myGrid"` is the alias of the Block Grid editor. + +If you are using ModelsBuilder, the example will look like this: + +```csharp +@await Html.GetBlockGridHtmlAsync(Model.MyGrid) +``` + +To use the `GetBlockGridHtmlAsync()` method, you will need to create a Partial View for each Block Type. The Partial View must be named using the alias of the Element Type that is being used as Content Model for the Block Type. + +These Partial View files need to go into the `Views/Partials/blockgrid/Components/` folder. + +Example: `Views/Partials/blockgrid/Components/MyElementTypeAliasOfContent.cshtml`. + +The Partial Views will receive a model of type `Umbraco.Cms.Core.Models.Blocks.BlockGridItem`. This model contains `Content` and `Settings` from your block, as well as the configured `RowSpan`, `ColumnSpan`, and `Areas` of the Block. + +#### Rendering the Block Areas + +The Partial View for the Block is responsible for rendering its own Block Areas. This is done using another built-in rendering mechanism: + +```csharp +@await Html.GetBlockGridItemAreasHtmlAsync(Model) +``` + +Here you will need to create a Partial View for each Block Type within the Block Area. For the name, use the alias of the Element Type that is being used as Content Model for the Block Type. + +These Partial Views must be placed in the same folder as before, (`Views/Partials/blockgrid/Components/`), and will receive a model of type `Umbraco.Cms.Core.Models.Blocks.BlockGridItem`. + +#### Putting it all together + +The following is an example of a Partial View for a Block Type of type `MyElementTypeAliasOfContent`. + +{% code title="MyElementTypeAliasOfContent.cshtml" %} +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; + +@* Render the value of field with alias 'heading' from the Element Type selected as Content section *@ +

@Model.Content.Value("heading")

+ +@* Render the block areas *@ +@await Html.GetBlockGridItemAreasHtmlAsync(Model) +``` +{% endcode %} + +If you are using ModelsBuilder, you can make the property rendering strongly typed by letting your view accept a model of type `BlockGridItem`. For example: + +{% code title="MyElementTypeAliasOfContent.cshtml" %} +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage>; +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; + +@* Render the Heading property from the Element Type selected as Content section *@ +

@Model.Content.Heading

+ +@* Render the block areas *@ +@await Html.GetBlockGridItemAreasHtmlAsync(Model) +``` +{% endcode %} + +#### Stylesheet + +Using the default rendering together with your layout stylesheet will provide what you need for rendering the layout. + +To use the Default Layout Stylesheet, copy the stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the `css` folder, example: `wwwroot/css/umbraco-blockgridlayout.css`. + +```csharp + +``` + +{% hint style="info" %} +A set of built-in Partial Views are responsible for rendering the Blocks and Areas in a Block Grid. If you want to tweak or change the way the Block Grid is rendered, you can use the built-in Partial Views as a template: + +1. Clone the views from [GitHub](https://github.com/umbraco/Umbraco-CMS/tree/main/src/Umbraco.Web.UI/Views/Partials/blockgrid). They can be found in `src/Umbraco.Web.UI/Views/Partials/blockgrid` . +2. Copy the cloned views to the local folder `Views/Partials/blockgrid/` . +3. Make changes to your copied views. The entry point for `GetBlockGridHtmlAsync()` is the view `default.cshtml` . +{% endhint %} + +### 2. Build custom rendering + +The built-in value converter for the Block Grid property editor lets you use the block data as you like. Call the `Value` method with a type of `BlockGridModel` to have the stored value returned as a `BlockGridModel` instance. + +`BlockGridModel` contains the Block Grid configuration (like the number of columns as `GridColumns`) whilst also being an implementation of `IEnumerable` (see details for `BlockGridItem` above). + +The following example mimics the built-in rendering mechanism for rendering Blocks using Partial Views: + +{% code title="View.cshtml" %} +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using Umbraco.Cms.Core.Models.Blocks +@{ + var grid = Model.Value("myGrid"); + + // get the number of columns defined for the grid + var gridColumns = grid.GridColumns; + + // iterate the block items + foreach (var item in grid) + { + var content = item.Content; + + @await Html.PartialAsync("PathToMyFolderOfPartialViews/" + content.ContentType.Alias, item); + } +} +``` +{% endcode %} + +If you do not want to use Partial Views, you can access the block item data directly within your rendering: + +{% code title="View.cshtml" %} +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using Umbraco.Cms.Core.Models.Blocks +@{ + var grid = Model.Value("myGrid"); + + // get the number of columns defined for the grid + var gridColumns = grid.GridColumns; + + // iterate the block items + foreach (var item in grid) + { + // get the content and settings of the block + var content = item.Content; + var settings = item.Settings; + // get the areas of the block + var areas = item.Areas; + // get the dimensions of the block + var rowSpan = item.RowSpan; + var columnSpan = item.ColumnSpan; + + // render the block data +
+

@(content.Value("title"))

+ This block is supposed to span @rowSpan rows and @columnSpan columns +
+ } +} +``` +{% endcode %} + +## Write a Custom Layout Stylesheet + +The default layout stylesheet is using CSS Grid. This can be modified to fit your implementation and your project. + +### Adjusting the Default Layout Stylesheet + +To make additions or overwrite parts of the default layout stylesheet, import the default stylesheet at the top of your own file. + +```css +@import 'css/umbblockgridlayout.css'; +``` + +You need to copy the Default Layout Stylesheet to your frontend. You can download the default layout stylesheet from the link within the DataType, we recommend putting the file in the `css` folder, example: `wwwroot/css/umbraco-blockgridlayout.css`. + +### Write a new Layout Stylesheet + +In this case, you would have to write the layout from scratch. + +You are free to pick any style, meaning there is no requirement to use CSS Grid. It is, however, recommended to use CSS Grid to ensure complete compatibility with the Umbraco backoffice. + +### CSS Class structure and available data + +When extending or writing your own layout, you need to know the structure and what data is available. + +For example: You can use the below HTML structure: + +```html +
+ + +
+ + +
+ + + + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+``` + +## Build a Custom Backoffice View + +Building Custom Views for Block representations in Backoffice is based on the same API for all Block Editors. + +[Read about building a Custom View for Blocks here](../../../../../customizing/extending-overview/extension-types/block-custom-view.md) + +## Creating a Block Grid programmatically + +In this example, we will be creating content programmatically for a "spot" Blocks in a Block Grid. + +1. On a Document Type add a property called **blockGrid**. +2. Then add as editor **Block Grid**. +3. In the Block Grid add a new block and click to **Create new Element Type** +4. Name this element type **spotElement** with the following properties: + +* A property called **title** with the editor of **Textstring** +* A property called **text** with the editor of **Textstring** + +5. Then on the **Settings model** click to add a new Setting. +6. Then click to **Create new Element Type**. +7. Name this element type **spotSettings** with the following properties: + +* A property called **featured** with the editor of **True/false**. + +![Block Grid - Block Configuration](../../../images/BlockEditorConfigurationProgramatically.png) + +The raw input data for the spots looks like this: + +```csharp +new[] +{ + new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1 }, + new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2 } +} +``` + +The resulting JSON object stored for the Block Grid will look like this: + +```json +{ + "layout": { + "Umbraco.BlockGrid": [{ + "contentUdi": "umb://element/bb23fe28160941efa506da7aa314172d", + "settingsUdi": "umb://element/9b832ee528464456a8e9a658b47a9801", + "areas": [], + "columnSpan": 12, + "rowSpan": 1 + }, { + "contentUdi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", + "settingsUdi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", + "areas": [], + "columnSpan": 6, + "rowSpan": 2 + } + ] + }, + "contentData": [{ + "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", + "udi": "umb://element/bb23fe28160941efa506da7aa314172d", + "title": "Item one", + "text": "This is item one" + }, { + "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", + "udi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", + "title": "Item two", + "text": "This is item two" + } + ], + "settingsData": [{ + "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", + "udi": "umb://element/9b832ee528464456a8e9a658b47a9801", + "featured": "0" + }, { + "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", + "udi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", + "featured": "1" + } + ] +} +``` + +For each item in the raw data, we need to create: + +* One `contentData` entry with the _title_ and _text_. +* One `settingsData` entry with the _featured_ value (the checkbox expects `"0"` or `"1"` as data value). +* One `layout` entry with the desired column and row spans. + +All `contentData` and `layoutData` entries need their own unique `Udi` as well as the ID (key) of their corresponding Element Types. In this sample, we only have one Element Type for content (`spotElement`) and one for settings (`spotSettings`). In a real life scenario, there could be any number of Element Type combinations. + +8. First and foremost, we need models to transform the raw data into Block Grid compatible JSON. Create a class called **Model.cs** containing the following: + +{% code title="Models.cs" lineNumbers="true" %} +```csharp +using Umbraco.Cms.Core; +using System.Text.Json.Serialization; +namespace My.Site.Models; + +// this is the "root" of the block grid data +public class BlockGridData +{ + public BlockGridData(BlockGridLayout layout, BlockGridElementData[] contentData, BlockGridElementData[] settingsData) + { + Layout = layout; + ContentData = contentData; + SettingsData = settingsData; + } + + [JsonPropertyName("layout")] + public BlockGridLayout Layout { get; } + + [JsonPropertyName("contentData")] + public BlockGridElementData[] ContentData { get; } + + [JsonPropertyName("settingsData")] + public BlockGridElementData[] SettingsData { get; } +} + +// this is a wrapper for the block grid layout, purely required for correct serialization +public class BlockGridLayout +{ + public BlockGridLayout(BlockGridLayoutItem[] layoutItems) => LayoutItems = layoutItems; + + [JsonPropertyName("Umbraco.BlockGrid")] + public BlockGridLayoutItem[] LayoutItems { get; } +} + +// this represents an item in the block grid layout collection +public class BlockGridLayoutItem +{ + public BlockGridLayoutItem(Udi contentUdi, Udi settingsUdi, int columnSpan, int rowSpan) + { + ContentUdi = contentUdi; + SettingsUdi = settingsUdi; + ColumnSpan = columnSpan; + RowSpan = rowSpan; + } + + [JsonPropertyName("contentUdi")] + public Udi ContentUdi { get; } + + [JsonPropertyName("settingsUdi")] + public Udi SettingsUdi { get; } + + [JsonPropertyName("areas")] + // areas are omitted from this sample for abbreviation + public object[] Areas { get; } = { }; + + [JsonPropertyName("columnSpan")] + public int ColumnSpan { get; } + + [JsonPropertyName("rowSpan")] + public int RowSpan { get; } + +} + +// this represents an item in the block grid content or settings data collection +public class BlockGridElementData +{ + public BlockGridElementData(Guid contentTypeKey, Udi udi) + { + ContentTypeKey = contentTypeKey; + Udi = udi; + } + + [JsonPropertyName("contentTypeKey")] + public Guid ContentTypeKey { get; } + + [JsonPropertyName("udi")] + public Udi Udi { get; } + + [JsonExtensionData] + public Dictionary? Data { get; set;} +} +``` +{% endcode %} + +9. By injecting [ContentService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html) and [ContentTypeService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentTypeService.html) into an API controller, we can transform the raw data into Block Grid JSON. It can then be saved to the target content item. Create a class called **BlockGridTestController.cs** containing the following: + +{% code title="BlockGridTestController.cs" lineNumbers="true" %} +```csharp +using Microsoft.AspNetCore.Mvc; +using My.Site.Models; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; + +namespace My.Site.Controllers; + +[ApiController] +[Route("/umbraco/api/blockgridtest")] +public class BlockGridTestController : Controller +{ + private readonly IContentService _contentService; + private readonly IContentTypeService _contentTypeService; + private readonly IJsonSerializer _serializer; + + public BlockGridTestController(IContentService contentService, IContentTypeService contentTypeService, IJsonSerializer serializer) + { + _contentService = contentService; + _contentTypeService = contentTypeService; + _serializer = serializer; + } + + // POST: /umbraco/api/blockgridtest/create + [HttpPost("create")] + public ActionResult Create() + { + // get the item content to modify + IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b")); + if (content == null) + { + return NotFound("Could not find the content item to modify"); + } + + // get the element types for spot blocks (content and settings) + IContentType? spotContentType = _contentTypeService.Get("spotElement"); + IContentType? spotSettingsType = _contentTypeService.Get("spotSettings"); + if (spotContentType == null || spotSettingsType == null) + { + return NotFound("Could not find one or more content types for block data"); + } + + // this is the raw data to insert into the block grid + var rawData = new[] + { + new { Title = "Item one", Text = "This is item one", Featured = false, ColumnSpan = 12, RowSpan = 1 }, + new { Title = "Item two", Text = "This is item two", Featured = true, ColumnSpan = 6, RowSpan = 2 } + }; + + // build the individual parts of the block grid data from the raw data + var layoutItems = new List(); + var spotContentData = new List(); + var spotSettingsData = new List(); + foreach (var data in rawData) + { + // generate new UDIs for block content and settings + var contentUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); + var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); + + // create a new layout item + layoutItems.Add(new BlockGridLayoutItem(contentUdi, settingsUdi, data.ColumnSpan, data.RowSpan)); + + // create new content data + spotContentData.Add(new BlockGridElementData(spotContentType.Key, contentUdi) + { + Data = new Dictionary + { + { "title", data.Title }, + { "text", data.Text }, + } + }); + + // create new settings data + spotSettingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsUdi) + { + Data = new Dictionary + { + { "featured", data.Featured ? "1" : "0" }, + } + }); + } + + // construct the block grid data from layout, content and settings + var blockGridData = new BlockGridData( + new BlockGridLayout(layoutItems.ToArray()), + spotContentData.ToArray(), + spotSettingsData.ToArray()); + + // serialize the block grid data as JSON and save it to the "blockGrid" property on the content item + var propertyValue = _serializer.Serialize(blockGridData); + content.SetValue("blockGrid", propertyValue); + _contentService.Save(content); + + return Ok("Saved"); + } +} +``` +{% endcode %} + +For the above code `IContent? content = _contentService.GetById(1203);` change the id with your content node that is using the Block Grid. + +10. In order to test this implementation, run the project and add `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved** then check your content node and you will see the 2 spotElement contents. + +![Block Grid - Result](../../../images/BlockEditorContentCreated.png) + +_This can also be tested via Postman as well if preffered._ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-level-variance.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-level-variance.md new file mode 100644 index 00000000000..339e0404f8c --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-level-variance.md @@ -0,0 +1,68 @@ +--- +description: An intro to achieving content variance at block level. +--- + +# Block Level Variance + +In a variant context, a Block Editor behaves like any other Umbraco property editor by default. The Blocks contained within the editor "belong" to the Document variant, and there is no connection between Blocks across variants. + +In other words, both Block content and structure can vary between each Document variant. + +![Default Block Editor behavior in the backoffice](images/block-level-variance-1.png) + +This is the desired behavior for many cases. However, in some cases it is preferable to have a shared Block structure across all variants, where only the Block content varies. + +This is known as Block Level Variance: + +![Block Level Variance in the backoffice](images/block-level-variance-2.png) + +Block Level Variance is achieved when: + +* The [Document Type](../../../../data/defining-content/default-document-types.md#document-type) is configured for variance, and +* The Block Editor property is _not_ configured for variance, and +* The Block Editor property editor is configured to use [Element Types](../../../../data/defining-content/default-document-types.md#element-type) that _do_ vary. + +## The "unexposed" Block state + +When adding a new _variant_ Block to one Document variant, it is automatically added to all variants of the Document. + +The Block will start out in an "unexposed" state for all other Document variants than the one where it was added. It will remain like that for each variant until it is edited in that variant. + +The "unexposed" state is visualized by a dimmed-down icon and title (or likely a missing title, if [Umbraco Flavored Markdown](../../../../../reference/umbraco-flavored-markdown.md) is used): + +![Block Level Variance in the backoffice - with an unexposed block](images/block-level-variance-3.png) + +{% hint style="info" %} +"Unexposed" Blocks are omitted from the published Document output. So, you do not need to worry about defensive coding to avoid rendering these Blocks. +{% endhint %} + +## Invariance vs. Block Level Variance + +It is entirely possible to mix and match variance and invariance within the scope of Block Level Variance. Invariance is fully supported, both at Block level and at Block property level. + +Invariance within Block Level Variance follows the same rules as invariance at Document level: + +- Invariant content is added to and updated across all Document variants. +- Invariant content is explicitly published for all published Document variants when one or more variants are published. + +### Examples + +Consider a Document with English and Danish language variants, which is published in both languages. + +- An editor opens the English variant. +- They add an invariant Block, and +- They re-publish the English variant. + +**Result:** The new block will appear in both the English and Danish published content. + +- An editor opens the Danish variant. +- They update an invariant property value in a variant Block, and +- They re-publish the Danish variant. + +**Result:** The updated property value appears in both the English and Danish published content. + +## Structure vs. Block Level Variance + +The Block Editor structure is _invariant_ for Block Level Variance. This means that the structure follows the same rules for invariance as outlined in the section above. + +In other words: If an editor changes the order of the Blocks in one Document variant, it changes for all Document variants. The change is applied to all published Document variants, as soon as one or more variants are published. diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md new file mode 100644 index 00000000000..e16e34f4005 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor.md @@ -0,0 +1,248 @@ +# Block List + +`Schema Alias: Umbraco.BlockList` + +`UI Alias: Umb.PropertyEditorUi.BlockList` + +`Returns: IEnumerable` + +{% hint style="warning" %} +This article is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +**Block List** is a list editing property editor, using [Element Types](../../../../data/defining-content/#element-types) to define the list item schema. + +{% hint style="info" %} +The _Block List_ replaces the obsolete _Nested Content_ editor. +{% endhint %} + +## Configure Block List + +The Block List property editor is configured in the same way as any standard property editor, via the _Data Types_ admin interface. + +To set up your Block List Editor property, create a new _Data Type_ and select **Block List** from the list of available property editors. + +Then you will see the configuration options for a Block List as shown below. + +![Block List - Data Type Definition](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType.jpg) + +The Data Type editor allows you to configure the following properties: + +* **Available Blocks** - Here you will define the Block Types to be available for use in the property. Read more on how to set up Block Types below. +* **Amount** - Sets the minimum and/or maximum number of blocks that should be allowed in the list. +* **Single block mode** - When in Single block mode, the output will be `BlockListItem<>` instead of `BlockListModel` +* **Live editing mode** - Enabling this will make editing of a block happening directly to the document model, making changes appear as you type. +* **Inline editing mode** - Enabling this will change editing experience to inline, meaning that editing the data of blocks happens at sight as accordions. +* **Property editor width** - Overwrite the width of the property editor. This field takes any valid css value for "max-width". + +## Setup Block Types + +Block Types are **Element Types** which need to be created before you can start configuring them as Block Types. This can be done either directly from the property editor setup process, or you can set them up beforehand and add them to the block list after. + +Once you have added an element type as a Block Type on your Block List Data Type you will have the option to configure it further. + +![Block List - Data Type Block Configuration](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_DataType_Blocks.png) + +Each Block has a set of properties that are optional to configure. They are described below. + +### Editor Appearance + +By configuring the properties in the group you can customize the user experience for your content editors when they work with the blocks in the Content section. + +* **Label** - Define a label for the appearance of the Block in the editor. The label uses [Umbraco Flavoured Markdown](../../../../../reference/umbraco-flavored-markdown.md) to display values of properties. The label is also used for search in the **Add Block** dialog during content editing. If no label is defined, the block will not be searchable. The search does not fall back to the block’s name. +* **Overlay editor size** - Set the size for the Content editor overlay for editing this block. + +### Data Models + +It is possible to use two separate Element Types for your Block Types. Its required to have one for Content and optional to add one for Settings. + +* **Content model** - This presents the Element Type used as model for the content section of this Block. This cannot be changed, but you can open the Element Type to perform edits or view the properties available. Useful when writing your Label. +* **Settings model** - Add a Settings section to your Block based on a given Element Type. When picked you can open the Element Type or choose to remove the settings section again. + +### Catalogue appearance + +These properties refer to how the Block is presented in the Block catalogue, when editors choose which Blocks to use for their content. + +* **Background color** - Define a background color to be displayed beneath the icon or thumbnail. Eg. `#424242`. +* **Icon color** - Change the color of the Element Type icon. Eg. `#242424`. +* **Thumbnail** - Pick an image or SVG file to replace the icon of this Block in the catalogue. + +The thumbnails for the catalogue are presented in the format of 16:10, and we recommend a resolution of 400px width and 250px height. + +### Advanced + +These properties are relevant when you work with custom views. + +* **Force hide content editor** - If you made a custom view that enables you to edit the content part of a block and you are using default editing mode (not inline) you might want to hide the content-editor from the block editor overlay. + +## Editing Blocks + +When viewing a **Block List** editor in the Content section for the first time, you will be presented with the option to Add content. + +![Block List - Add Content](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContent.png) + +Clicking the Add content button brings up the Block Catalogue. + +![Block List - Setup](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker_simplesetup.jpg) + +The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance. + +![Block List - example setup from Umbraco.com](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_BlockPicker.jpg) + +Click the Block Type you wish to create and a new Block will appear in the list. + +Depending on whether your Block List Editor is setup to use default or inline editing mode you will see one of the following things happening: + +In default mode you will enter the editing overlay of that Block: + +![Block List - Overlay editing](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_EditingOverlay.jpg) + +In inline editing mode the new Blocks will expand to show its inline editor: + +![Block List - Inline editing](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_InlineEditing.jpg) + +More Blocks can be added to the list by clicking the Add content button or using the inline Add content button that appears on hover between or above existing Blocks. + +![Block List - Add Content](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockListEditor_AddContentInline.jpg) + +To reorder the Blocks, click and drag a Block up or down to place in the desired order. + +To delete a Block click the trash-bin icon appearing on hover. + +## Rendering Block List Content + +Rendering the stored value of your **Block List** property can be done in two ways. + +### 1. Default rendering + +You can choose to use the built-in rendering mechanism for rendering blocks via a Partial View for each block. + +The default rendering method is named `GetBlockListHtml()` and comes with a few options to go with it. The typical use could be: + +```csharp +@Html.GetBlockListHtml(Model, "MyBlocks") +``` + +"MyBlocks" above is the alias for the Block List editor. + +If using ModelsBuilder the example can be simplified: + +Example: + +```csharp +@Html.GetBlockListHtml(Model.MyBlocks) +``` + +To make this work you will need to create a Partial View for each block, named by the alias of the Element Type that is being used as Content Model. + +These partial views must be placed in this folder: `Views/Partials/BlockList/Components/`. Example: `Views/Partials/BlockList/Components/MyElementTypeAliasOfContent.cshtml`. + +A Partial View will receive the model of `Umbraco.Core.Models.Blocks.BlockListItem`. This gives you the option to access properties of the Content and Settings section of your Block. + +In the following example of a Partial view for a Block Type, please note that the `MyElementTypeAliasOfContent`and `MyElementTypeAliasOfSettings` should correspond with the selected Element Type Alias for the given model in your case. + +Example: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ + var content = (ContentModels.MyElementTypeAliasOfContent)Model.Content; + var settings = Model.Settings as ContentModels.MyElementTypeAliasOfContent; // Cast Model.Settings safely using 'as' to avoid null reference exceptions +} + +@* Output the value of field with alias 'heading' from the Element Type selected as Content section *@ +

@content.Value("heading")

+``` + +With ModelsBuilder: + +```csharp +@* Output the value of field with alias 'heading' from the Element Type selected as Content section *@ +

@content.Heading

+``` + +### 2. Build your own rendering + +A built-in value converter is available to use the data as you like. Call the `Value` method with a generic type of `IEnumerable` and the stored value will be returned as a list of `BlockListItem` entities. + +Example: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; +@using Umbraco.Cms.Core.Models.Blocks; +@{ + var blocks = Model.Value>("myBlocksProperty"); + foreach (var block in blocks) + { + var content = block.Content; + + @Html.Partial("MyFolderOfBlocks/" + content.ContentType.Alias, block) + } +} +``` + +Each item is a `BlockListItem` entity that contains two main properties `Content` and `Settings`. Each of these is a `IPublishedElement` which means you can use all the value converters you are used to using. + +Example: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@using Umbraco.Cms.Core.Models.Blocks; +@{ + var blocks = Model.Value>("myBlocksProperty"); + foreach (var block in blocks) + { + var content = (ContentModels.MyAliasOfContentElementType)block.Content; + var settings = (ContentModels.MyAliasOfSettingsElementType)block.Settings; + +

@content.MyExampleHeadlinePropertyAlias

+ } +} +``` + +## Extract Block List Content data + +In some cases, you might want to use the Block List Editor to hold some data and not necessarily render a view since the data should be presented in different areas on a page. An example could be a product page with variants stored in a Block List Editor. + +In this case, you can extract the variant's data using the following, which returns `IEnumerable`. + +Example: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage; +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@using Umbraco.Cms.Core.Models.Blocks; +@{ + var variants = Model.Value>("variants").Select(x => x.Content); + foreach (var variant in variants) + { +

@variant.Value("variantName")

+

@variant.Value("description")

+ } +} +``` + +If using ModelsBuilder the example can be simplified: + +Example: + +```csharp +@inherits Umbraco.Web.Mvc.UmbracoViewPage +@using ContentModels = Umbraco.Web.PublishedModels; +@{ + var variants = Model.Variants.Select(x => x.Content).OfType(); + foreach (var variant in variants) + { +

@variant.VariantName

+

@variant.Description + } +} +``` + +If you know the Block List Editor only uses a single block, you can cast the collection to a specific type `T` using `.OfType()` otherwise the return value will be `IEnumerable`. + +## Build a Custom Backoffice View + +Building Custom Views for Block representations in Backoffice is the same for all Block Editors. [Read about building a Custom View for Blocks here](../../../../../customizing/extending-overview/extension-types/block-custom-view.md) diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-1.png new file mode 100644 index 00000000000..437c13e81e8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-2.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-2.png new file mode 100644 index 00000000000..e20614bac8a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-2.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-3.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-3.png new file mode 100644 index 00000000000..35b5a386e49 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/images/block-level-variance-3.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md new file mode 100644 index 00000000000..a548f410b35 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/checkbox-list.md @@ -0,0 +1,107 @@ +# Checkbox List + +`Schema Alias: Umbraco.CheckBoxList` + +`UI Alias: Umb.PropertyEditorUi.CheckBoxList` + +`Returns: IEnumerable` + +Displays a list of preset values as a list of checkbox controls. The text saved is an IEnumerable collection of the text values. + +{% hint style="info" %} +Unlike other property editors, the Option IDs are not directly accessible in Razor. +{% endhint %} + +## Data Type Definition Example + +![True/Checkbox List Definition](images/checkbox-list-setup.png) + +{% hint style="info" %} +You can use dictionary items to translate the options in a Checkbox List property editor in a multilingual setup. For more details, see the [Creating a Multilingual Site](../../../../tutorials/multilanguage-setup.md#translating-multi-value-property-editors) article. +{% endhint %} + +## Content Example + +![Checkbox List Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/checkbox-list-content.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (Model.HasValue("superHeros")) + { +

    + @foreach (var item in Model.Value>("superHeros")) + { +
  • @item
  • + } +
+ } +} +``` + +### With Models Builder + +```csharp +@{ + if (Model.SuperHeros.Any()) + { +
    + @foreach (var item in Model.SuperHeros) + { +
  • @item
  • + } +
+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Serialization +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@inject IJsonSerializer Serializer +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'superHeroes'. + content.SetValue("superHeroes", Serializer.Serialize(new[] { "Umbraco", "CodeGarden"})); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'superHeroes' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.SuperHeroes).Alias, Serializer.Serialize(new[] { "Umbraco", "CodeGarden"})); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md new file mode 100644 index 00000000000..89b88a394a6 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md @@ -0,0 +1,116 @@ +# Collection + +`Schema Alias: Umbraco.ListView` + +`UI Alias: Umb.PropertyEditorUi.Collection` + +`Returns: IEnumerable` + +**Collection** displays a collection of categories when it is enabled on a Document Type with children. + +![Collection example](images/listview-v14.png) + +## Configure Collection + +Once Collections are configured, the parent content item displays its child items in a list view format within the content item itself. If Collections are not configured, the child items are displayed directly in the Content Tree, rather than being grouped within the parent content item. + +![Enable Collection example](images/enable-listview-v14.png) + +## Settings + +![Collection settings example](../../../../.gitbook/assets/collection-settings-example-15-1.png) + +### Columns Displayed + +It is possible to add more columns to the collection, via adding the properties through the picker modal. These properties are based on the Data Types which are used by the Document Type. The properties will listed for selection. + +![Collection property picker example](images/collection-property-picker.png) + +Once you have selected a column you want to display, define what its heading label should be and what kind of value it should display. You can also move the headers around, re-ordering how they should look. This is done by the move icon on the left side of the alias. + +The template section is where you define what kind of value you want to display. The value of the column is in the `value` variable. + +### Layouts + +Collection comes with two layouts by default. A list and a grid view. These views can be disabled if you are not interested in any of them. + +{% hint style="info" %} +A minimum of one layout needs to be enabled for Collection to work. +{% endhint %} + +You can also make your own layout and add it to the settings. For example, if you wanted to change the width or length of the grid, you will be able to do so. + +### Order By + +Will sort your collection by the selection you choose in the dropdown. By default it selects "Last edited" and you get the following three columns: + +* **Last edited** - When the content node was last edited and saved. +* **Name** - Name of the content node(s). +* **Created by** - This is the user who the content node was created by. + +You can add more sorting to this collection by adding more datatypes to the columns in the "Columns Displayed" section. + +### Order Direction + +You can select order of the content nodes displayed, "Ascending [a-z]" or "Descending [z-a]". The order is affected by the "Order By" selection. + +### Page Size + +Defines how many child content nodes you want to see per page. This will limit how many content items you will see in your collection. If you set it to 5, then only 5 content items will be shown in the collection. + +### Workspace View icon + +{% hint style="info" %} +Support for changing the Workspace View icon has not been implemented yet. +{% endhint %} + +Changes the icon in the backoffice of the collection. By default it will look like the image below. + +![Collection icon example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/list-icon.png) + +### Workspace View name + +{% hint style="info" %} +Support for changing the Workspace View name has not been implemented yet. +{% endhint %} + +You can change the name of the collection itself. Default if empty: 'Child Items'. + +### Show Content Workspace View First + +{% hint style="info" %} +Support for setting the Content Workspace View First has not been implemented yet. +{% endhint %} + +Enable this to show the Content Workspace View by default instead of the collection's. + +## Content Example + +### Generic field value + +This example shows how to use a generic field from a child item and display its value in a collection. + +![Collection content email label template](images/collection-label-template.png) + +You can use the [Umbraco Flavored Markdown](../../../../reference/umbraco-flavored-markdown.md) syntax to display the label value. Here, the `{=value}` placeholder retrieves the value of the *Email* property and displays it in the collection, as shown in the image below: + +![Collection content email value displayed](images/collections-display-email.png) + +### Content name + +First, a Content Picker property needs to be present on the content item. In this example, the `child item` has gotten a Content Picker Data Type with the alias of `contentPicker`. + +![Collection content picker](images/content-picker-property.png) + +The child item has a document and the value that should be displayed is the name of the picked value. The next step is to reconfigure the template value in the collection setting. + +![Collection content picker](images/collection-column-content-picker.png) + +This will take the value picked up by the content picker. + +![Collection content picker with picked value](images/content-picker-picked-value.png) + +And display it in the collection. Shown in the example below: + +![Collection view cards with content picker value](images/collection-view-cards-content-picker.png) + diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md new file mode 100644 index 00000000000..b98eb924638 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/color-picker.md @@ -0,0 +1,124 @@ +# Color Picker + +`Schema Alias: Umbraco.ColorPicker` + +`UI Alias: Umb.PropertyEditorUi.ColorPicker` + +`Returns: String (Hexadecimal)` + +`Returns: Umbraco.Cms.Core.PropertyEditors.ValueConverters.ColorPickerValueConverter.PickedColor (When using labels)` + +The Color picker allows you to set some predetermined colors that the editor can choose between. + +It is possible to add a label to use with the color. + +## Data Type Definition Example + +![Color Picker Data Type Definition](images/Color-Picker-DataType.png) + +## Content Example + +![Color Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Color-Picker-Content-v8.png) + +## Example with Models Builder + +```csharp +@{ + // Model has a property called "Color" which holds a Color Picker editor + var hexColor = Model.Color; + // Define the label if you've included it + String colorLabel = Model.Color.Label; + + if (hexColor != null) + { +
@colorLabel
+ } +} +``` + +## Example without Models Builder + +```csharp +@using Umbraco.Cms.Core.PropertyEditors.ValueConverters +@{ + // Model has a property called "Color" which holds a Color Picker editor + var hexColor = Model.Value("Color"); + // Define the label if you've included it + var colorLabel = Model.Value("Color").Label; + + if (hexColor != null) + { +
@colorLabel
+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +### Without labels + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'color'. + // The value set here, needs to be one of the colors on the Color Picker + content.SetValue("color", "38761d"); + + // Save the change + ContentService.Save(content); +} +``` + +### With labels + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'color'. + // The value set here, needs to be one of the colors on the Color Picker + content.SetValue("color", "{'value':'000000', 'label':'Black', 'sortOrder':1, 'id':'1'}"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'color' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Color).Alias, "38761d"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md new file mode 100644 index 00000000000..4548605ef3e --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/content-picker.md @@ -0,0 +1,284 @@ +# Content Picker + +`Schema Alias: Umbraco.ContentPicker` + +`UI Alias: Umb.PropertyEditorUi.DocumentPicker` + +`Returns: IEnumerable` + +The Content Picker enables choosing the type of content tree to display and which specific part to render. It also allows you to set a dynamic root node for the content based on the current document using the Content Picker. + +{% hint style="info" %} +The Content Picker was formerly known as the **Multinode Treepicker** in version 13 and below. + +The renaming is purely a client-side UI change, meaning the property editor still uses the `Umbraco.MultiNodeTreePicker` schema alias. + +The change was made as the word **Content** in the backoffice acts as an umbrella term covering Documents, Media, and Members. + +**Are you looking for the original Content Picker?** + +The Content Picker from version 13 and below has been renamed [Document Picker](document-picker.md). +{% endhint %} + +## Data Type Definition Example + +![Content Picker Data Type Settings](../../../../.gitbook/assets/ContentPicker-data-type-definition.png) + +### Minimum/maximum number of items + +Define a limit on the number of items allowed to be selected. + +### Ignore user start nodes + +Checking this field allows users to choose nodes they normally cannot access. + +### Node Type + +This option allows for configuring what type of content is available when using the Data Type. The available types of content are Content, Members, or Media items. + +When selecting Content from the dropdown, the option to specify a root node, also called the **origin**, becomes available. + +

The option to specify a root node also called the "origin" becomes available when Content is selected as the Node Type.

+ + + +When picking the **origin** there are several different options available: + +

The available options for setting a root node (origin) for the Content Picker.

+ +The following options are available when picking the origin: + +* **Root**: The root is the first level item of the sub-tree of the current node. +* **Parent**: The parent is the nearest ancestor of the current node. +* **Current**: The current node. + * A picker that uses the current node, cannot pick anything when the current node is created, as it will not have any children. +* **Site**: The nearest ancestor of the current node with a domain assigned. +* **Specific node**: A specific node selected from the existing content. + +When an origin has been specified, it becomes possible to continue to build a _Dynamic Root_ by adding additional query steps. + +Navigate the content tree relative to the specified origin to execute multiple query steps and find the root node needed. + +![The default options for executing additional steps to locate the Dynamic Root.](../../../../.gitbook/assets/append-step-to-query.png) + +The following options are available: + +* **Nearest Ancestor or Self:** Find the nearest ancestor or current item that fits with one of the configured Document Types. +* **Furthest Ancestor or Self:** Find the furthest ancestor or current item that fits with one of the configured Document Types. +* **Nearest Descendant or Self:** Find the nearest descendant or current item that fits with one of the configured Document Types. +* **Furthest Descendant or Self:** Find the furthest descendant or current item that fits with one of the configured Document Types. + +The options above are all based on navigating the document hierarchy by locating ancestors and descendants. It is possible to execute **custom steps** to build even more complex queries. Once a custom query is available it will be added to the bottom of the _Append steps to query_ dialog. Learn more about [adding custom query steps in the section below](content-picker.md#adding-a-custom-query-step). + +Each query step takes the output from the origin or the previous step as input. It is only ever the result of the last query step that is passed to the next step. + +![Query steps appended to a Content Picker with the type Content.](../../../../.gitbook/assets/content-picker-query-steps.png) + +#### Adding a custom query step + +Custom query steps can be used to solve specific use cases, such as traversing sibling documents or matching property values. Before the custom query steps can be selected in the Data Type settings, they must be defined via code. + +When implementing a query step it requires a collection of origins and information about the query step. The collection is taken from where the name specified in the UI can be found. + +{% hint style="warning" %} +**Specifying the origin is required** for the custom query step to become available. + +Read the [Node Type section](content-picker.md#node-type) above to learn more about this. +{% endhint %} + +You can inject dependencies into the constructor. These dependencies could be custom repositories or the `IVariationContextAccessor`, if you want to use the current culture. + +The `ExecuteAsync` method receives a set of content keys from the last executed query step or the origin. It has to return a new set of content keys. + +```csharp +public class MyCustomDynamicRootQueryStep : IDynamicRootQueryStep +{ + private readonly IMyCustomRepository _myCustomRepository; + + public MyCustomDynamicRootQueryStep(IMyCustomRepository myCustomRepository) + { + _myCustomRepository = myCustomRepository; + } + + // The string below is what you specify in the UI to execute this custom query step. + public virtual string SupportedDirectionAlias { get; set; } = "MyCustomStep"; + + public async Task>> ExecuteAsync(ICollection origins, DynamicRootQueryStep filter) + { + if (filter.Alias != SupportedDirectionAlias) + { + return Attempt>.Fail(); + } + + if (origins.Any() is false) + { + return Attempt>.Succeed(Array.Empty()); + } + + // Replace the following with your custom logic + var result = await _myCustomRepository.GetWhateverIWantAsync(origins); + + return Attempt>.Succeed(result); + } +} +``` + +To register the custom query step, append it to the existing query steps, `DynamicRootSteps()`. This is done from a composer as shown below. + +```csharp +public class CustomQueryStepComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DynamicRootSteps().Append(); + } +} +``` + +Finally, register the custom query step on the client side and provide a brief description. + +You can do this in an `umbraco-package.json` file, as shown below: + +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "My.Test.Extension", + "version": "0.1.0", + "extensions": [ + { + "type": "dynamicRootQueryStep", + "alias": "Umb.DynamicRootQueryStep.MyCustomStep", + "name": "Dynamic Root Query Step: My Custom Step", + "meta": { + "queryStepAlias": "MyCustomStep", + "label": "My Custom Step", + "description": "My custom step description.", + "icon": "icon-coffee" + }, + "weight": 0 + } + ] +} +``` + +### Allow items of type + +Choose which types of content should be available to pick using the Content Picker. + +This is done by selecting one or more Document Types. + +## Query Example + +Consider the following tree structure where the Document Type alias is presented in square brackets. + +* Codegarden + * 2023 \[`year`] + * Talks \[`talks`] + * ... + * Umbraco anno MMXXIII \[`talk`] + * Stages \[`stages`] + * Social Space \[`stage`] + * No 10 \[`stage`] + * No 16 \[`stage`] + * The Theatre \[`stage`] + * 2022 \[`year`] + * Talks \[`talks`] + * ... + * Stages \[`stages`] + * Main Stage \[`stage`] + * The Barn \[`stage`] + * The Theatre \[`stage`] + +Consider configuring a Content Picker on the `talk` Document Type to select a `stage` for the `talk`. Here, you want to display only the stages for the actual year. To do this, you need to set the parent as the origin. + +For instance, if you are on the `Umbraco anno MMXXIII` node, the collection of content keys passed into the first query step will only contain the `Talks` content node. + +* First, query for the nearest ancestors of the type `year`. This will return `2023`. +* Second, query for the nearest descendants of the type `stages`. + +When opening the picker on the `Umbraco anno MMXXIII` node, it will now show the children of the node on the path `Codegarden > 2023 > Stages`. + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + var typedContentPicker = Model.Value>("featuredArticles"); + if (typedContentPicker != null) { + foreach (var item in typedContentPicker) + { +

@item.Name

+ } +} +``` + +### With Models Builder + +```csharp +@{ + var typedContentPicker = Model.FeaturedArticles; + foreach (var item in typedContentPicker) + { +

@item.Name

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update the value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Get the pages you want to assign to the Content Picker + var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); + var anotherPage = Umbraco.Content("1f8cabd5-2b06-4ca1-9ed5-fbf14d300d59"); + + // Create Udi's of the pages + var pageUdi = Udi.Create(Constants.UdiEntityType.Document, page.Key); + var anotherPageUdi = Udi.Create(Constants.UdiEntityType.Document, anotherPage.Key); + + // Create a list of the page udi's + var udis = new List{pageUdi.ToString(), anotherPageUdi.ToString()}; + + // Set the value of the property with alias 'featuredArticles'. + content.SetValue("featuredArticles", string.Join(",", udis)); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'featuredArticles' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturedArticles).Alias, string.Join(",", udis)); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md new file mode 100644 index 00000000000..41a6b0bb150 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date-time.md @@ -0,0 +1,82 @@ +# DateTime + +`Schema Alias: Umbraco.DateTime` + +`UI Alias: Umb.PropertyEditorUi.DatePicker` + +`Returns: DateTime` + +Displays a calendar UI for selecting dates which are saved as a DateTime value. + +## Data Type Definition Example + +![Data Type Definiton](images/date-time.png) + +There is one setting available for manipulating the DateTime property. + +The setting involves defining the format. The default date format in the Umbraco backoffice is `YYYY-MM-DD HH:mm:ss`, but you can change it to a different format. See [MomentJS.com](https://momentjs.com/) for the supported formats. + +## Content Example + +![Content Example](../built-in-property-editors/images/date-picker-v8.png) + +## MVC View Example - displays a datetime + +### With Models Builder + +```csharp +@Model.DatePicker +``` + +### Without Models Builder + +```csharp +@Model.Value("datePicker") +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'datePicker' + content.SetValue("datePicker", DateTime.Now); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + + // Set the value of the property with alias 'datePicker' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.DatePicker).Alias, DateTime.Now); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md new file mode 100644 index 00000000000..f570390121e --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/date.md @@ -0,0 +1,39 @@ +# Date + +`Schema Alias: Umbraco.DateTime` + +`UI Alias: Umb.PropertyEditorUi.DatePicker` + +`Returns: Date` + +Displays a calendar UI for selecting dates which are saved as a DateTime value. + +## Data Type Definition Example + +![Data Type Definition Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/DateTime-DataType.png) + +The only setting that is available for manipulating the Date property is to set a format. By default the format of the date in the Umbraco backoffice will be `YYYY-MM-DD`, but you can change this to something else. See [MomentJS.com](https://momentjs.com/) for the supported formats. + +## Content Example + +![Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Date-Time-Content.png) + +## MVC View Example - displays a datetime + +### Typed + +```csharp +@(Model.Content.GetPropertyValue("datePicker").ToString("dd MM yyyy")) +``` + +### Dynamic (Obsolete) + +{% hint style="warning" %} +See [Common pitfalls](../../../../reference/common-pitfalls.md) for more information about why the dynamic approach is obsolete. +{% endhint %} + +```csharp +@{ + @CurrentPage.datePicker.ToString("dd-MM-yyyy") +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md new file mode 100644 index 00000000000..518b6d4ce3d --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/decimal.md @@ -0,0 +1,81 @@ +# Decimal + +`Schema Alias: Umbraco.Decimal` + +`UI Alias: Umb.PropertyEditorUi.Decimal` + +`Returns: decimal` + +## Data Type Definition Example + +![Decimal Content Example](images/content-example.png) + +In the example above the possible values for the input field would be \[8, 8.5, 9, 9.5, 10] + +_All other values will be removed in the content editor when saving or publishing._ + +If the value of **Step Size** is not set then all decimal values between 8 and 10 is possible to input in the content editor. + +## Content Example + +![Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example.png) + +## MVC View Example + +### With Models Builder + +```csharp +@Model.MyDecimal +``` + +### Without Models Builder + +```csharp +@Model.Value("MyDecimal") +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'myDecimal'. + content.SetValue("myDecimal", 3); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'myDecimal' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyDecimal).Alias, 3); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/document-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/document-picker.md new file mode 100644 index 00000000000..5f919303c6d --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/document-picker.md @@ -0,0 +1,104 @@ +# Document Picker + +`Schema Alias: Umbraco.ContentPicker` + +`UI Alias: Umb.PropertyEditorUi.DocumentPicker` + +`Returns: IPublishedContent` + +The Document Picker opens a panel to pick a specific page from the content structure. The value saved is the selected nodes [UDI](../../../../reference/querying/udi-identifiers.md). + +{% hint style="info" %} +The Document Picker was formerly known as the **Content Picker** in version 13 and below. + +The renaming is purely a client-side UI change, meaning the property editor still uses the `Umbraco.ContentPicker` schema alias. + +The change was made as the word **Content** in the backoffice acts as an umbrella term covering the terms Document, Media, and Member. +{% endhint %} + +## Data Type Definition Example + +![Document Picker Data Type Definition](images/Document-Picker-DataType.png) + +## Document Picker Example + +![Document Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Content-Picker-Content-v10.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + IPublishedContent typedContentPicker = Model.Value("featurePicker"); + if (typedContentPicker != null) + { +

@typedContentPicker.Name

+ } +} +``` + +### With Models Builder + +```csharp +@{ + IPublishedContent typedContentPicker = Model.FeaturePicker; + if (typedContentPicker != null) + { +

@typedContentPicker.Name

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Get the page you want to assign to the document picker + var page = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); + + // Create an Udi of the page + var udi = Udi.Create(Constants.UdiEntityType.Document, page.Key); + + // Set the value of the property with alias 'featurePicker'. + content.SetValue("featurePicker", udi.ToString()); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'featurePicker' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturePicker).Alias, udi.ToString()); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md new file mode 100644 index 00000000000..6eaba1e2b85 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/dropdown/README.md @@ -0,0 +1,134 @@ +# Dropdown + +`Schema Alias: Umbraco.DropDown.Flexible` + +`UI Alias: Umb.PropertyEditorUi.Dropdown` + +`Returns: String` or `IEnumerable` + +Displays a list of preset values. Either a single value or multiple values (formatted as a collection of strings) can be returned. + +## Settings + +### Enable multiple choice + +If enabled, editors will be able to select multiple values from the dropdown otherwise only a single value can be selected. + +### Add options + +Options are the values which are shown in the dropdown list. You can add, edit, or remove values here. + +{% hint style="info" %} +You can use dictionary items to translate the options in a Dropdown property editor in a multilingual setup. For more details, see the [Creating a Multilingual Site](../../../../../tutorials/multilanguage-setup.md#translating-multi-value-property-editors) article. +{% endhint %} + +## Data Type Definition Example + +![Dropdown-data-type](../images/Dropdown-DataType.png) + +## Content Example + +### Single Value + +![Single dropdown content example](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownSingle-Content.png) + +### Multiple Values + +![Multiple dropdown content example](../../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/dropdown/images/DropdownMultiple-Content.png) + +## MVC View Example + +### Single item - without Models Builder + +```csharp +@if (Model.HasValue("category")) +{ +

@(Model.Value("category"))

+} +``` + +### Multiple items - without Models Builder + +```csharp +@if (Model.HasValue("categories")) +{ + var categories = Model.Value>("categories"); +
    + @foreach (var category in categories) + { +
  • @category
  • + } +
+} +``` + +### Single item - with Models Builder + +```csharp +@if (!Model.HasValue(Model.Category)) +{ +

@Model.Category

+} +``` + +### Multiple items - with Models Builder + +```csharp +@if (Model.Categories.Any()) +{ +
    + @foreach (var category in Model.Categories) + { +
  • @category
  • + } +
+} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Serialization +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@inject IJsonSerializer Serializer +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'categories'. + content.SetValue("categories", Serializer.Serialize(new[] { "News" })); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'categories' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Categories).Alias, Serializer.Serialize(new[] { "News" })); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md new file mode 100644 index 00000000000..73085cfc942 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/email-address.md @@ -0,0 +1,79 @@ +--- +description: In this article you can learn how to use the build in email property editor +--- + +# Email Address + +`Schema Alias: Umbraco.EmailAddress` + +`UI Alias: Umb.PropertyEditorUi.EmailAddress` + +`Returns: String` + +Displays an email address. + +## Settings + +The Email Address Property Editor does not come with any further configuration. The property can be configured once it has been added to a Document Type. + +![Checkbox Example](images/emailaddress-datatype.png) + +## Content Example + +![Single email address content example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/EmailAddress-Content-v10.png) + +## MVC View Example + +### Without Modelsbuilder + +```csharp +@if (Model.HasValue("email")) +{ + var emailAddress = Model.Value("email"); +

@emailAddress

+} +``` + +### With Modelsbuilder + +```csharp +@if (!string.IsNullOrWhiteSpace(Model.Email)) +{ +

@Model.Email

+} +``` + +## Add value programmatically + +See the example below to learn how a value can be added or changed programmatically to an Email-address property. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services; + +@inject IContentService Services; +@{ + // Get access to ContentService + var contentService = Services; + + // Create a variable for the GUID of your page + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've just defined + var content = contentService.GetById(guid); + // Set the value of the property with alias 'email' + content.SetValue("email", "jpk@umbraco.dk"); + + // Save the change + contentService.Save(content); +} +``` + +{% hint style="info" %} +The value sent to an EmailAddress property needs to be a correct email address, For example: [name@domain.com](mailto:name@domain.com). + +It is recommended that you set up validation on this property, in order to verify whether the value added is in the correct format. +{% endhint %} diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md new file mode 100644 index 00000000000..bca4647fd88 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/eye-dropper-color-picker.md @@ -0,0 +1,92 @@ +# Eye Dropper Color Picker + +`Schema Alias: Umbraco.ColorPicker.EyeDropper` + +`UI Alias: Umb.PropertyEditorUi.EyeDropper` + +`Returns: string` + +The Eye Dropper Color picker allows you to choose a color from the full color spectrum using HEX and RGBA. + +## Data Type Definition Example + +![Eye Dropper Color Picker Data Type Definition](images/Eye-Dropper-Color-Picker-DataType.png) + +## Content Example + +![Eye Dropper Color Picker Content](images/Eye-Dropper-Color-Picker-Content.png) + +## Example with Models Builder + +```csharp +@{ + var color = Model.Color?.ToString(); + + if (color != null) + { + + } +} +``` + +## Example without Models Builder + +```csharp +@{ + var color = Model.Value("Color"); + + if (color != null) + { + + } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'color'. + content.SetValue("color", "#6fa8dc"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'color' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Color).Alias, "#6fa8dc"); + + // Set the value of the property with alias 'theme' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Theme).Alias, "rgba(111, 168, 220, 0.7)"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md new file mode 100644 index 00000000000..a57c312b4ee --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/file-upload.md @@ -0,0 +1,136 @@ +# File Upload + +`Schema Alias: Umbraco.UploadField` + +`UI Alias: Umb.PropertyEditorUi.UploadField` + +`Returns: string` + +Adds an upload field, which allows documents or images to be uploaded to Umbraco. + +You can define which file types should be accepted through the upload field. + +{% hint style="info" %} +For uploading and adding files and images to your Umbraco project, we recommend using the Media Picker. + +Find the full documentation for the property in the [Media Picker](media-picker-3.md) article. +{% endhint %} + +## Data Type Definition Example + +![File Upload Definition](images/file-upload-definition.png) + +## Content Example + +![Content Example Empty](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/content-example-empty.png) ![Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/File-Upload-content-example.png) + +In code, the property is a string, which references the location of the file. + +Example: `"/media/o01axaqu/guidelines-on-remote-working.pdf"` + +## MVC View Example + +### Without Models Builder + +```csharp +@using System.IO; +@{ + if (Model.HasValue("myFile")) + { + var myFile = Model.Value("myFile"); + + @System.IO.Path.GetFileName(myFile) + } + +} +``` + +### With Models Builder + +```csharp +@if (!Model.HasValue(Model.MyFile)) +{ + @System.IO.Path.GetFileName(Model.MyFile) +} +``` + +## Add values programmatically + +{% hint style="info" %} +The samples in this section have not been verified against the latest version of Umbraco. + +Instead, we recommend using the [Media Picker](media-picker-3.md) for uploading files to your Umbraco website. +{% endhint %} + +See the example below to see how a value can be added or changed programmatically. To update a value of this property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html) and the [Media Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.MediaService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.IO +@using Umbraco.Cms.Core.Serialization +@using Umbraco.Cms.Core.Strings +@inject MediaFileManager MediaFileManager +@inject IShortStringHelper ShortStringHelper +@inject IContentTypeBaseServiceProvider ContentTypeBaseServiceProvider +@inject IContentService ContentService +@inject IMediaService MediaService +@inject IJsonSerializer Serializer +@inject MediaUrlGeneratorCollection MediaUrlGeneratorCollection +@{ + // Create a variable for the GUID of the parent where you want to add a child item + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Create a variable for the file you want to upload, in this case the Our Umbraco logo + var imageUrl = "https://our.umbraco.com/assets/images/logo.svg"; + + // Create a request to get the file + var request = WebRequest.Create(imageUrl); + var webResponse = request.GetResponse(); + var responseStream = webResponse.GetResponseStream(); + + // Get the file name + var lastIndex = imageUrl.LastIndexOf("/", StringComparison.Ordinal) + 1; + var filename = imageUrl.Substring(lastIndex, imageUrl.Length - lastIndex); + + // Create a media file + var media = MediaService.CreateMediaWithIdentity("myImage", -1, "File"); + media.SetValue(MediaFileManager, MediaUrlGeneratorCollection, ShortStringHelper, ContentTypeBaseServiceProvider, Constants.Conventions.Media.File, filename, responseStream); + // Save the created media + MediaService.Save(media); + + // Get the published version of the media (IPublishedContent) + var publishedMedia = Umbraco.Media(media.Id); + + // Set the value of the property with alias 'myFile' + content.SetValue("myFile", publishedMedia.Url()); + + // Save the child item + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'myFile' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyFile).Alias, publishedMedia.Url(); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md new file mode 100644 index 00000000000..5a99d0b7b60 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/image-cropper.md @@ -0,0 +1,243 @@ +# Image Cropper + +`Schema Alias: Umbraco.ImageCropper` + +`UI Alias: Umb.PropertyEditorUi.ImageCropper` + +`Returns: MediaWithCrops` + +Returns a path to an image, along with information about focal point and available crops. + +When the Image Cropper is used on a Media Type the crops are shared between all usages of a Media Item. This is called **global crops**. + +If the Image Cropper is used on a Document Type, the file and crops will be **local** to the Document. + +Notice that it is possible make local crops on shared Media Items via the [Media Picker Property Editor](media-picker-3.md). + +## Settings + +### Define Crops + +You can add, edit & delete crop presets the cropper UI can use. + +## Data Type Definition Example + +![Image Cropper Data Type Definition](images/imageCropper.png) + +## Content Example + +The Image Cropper provides a UI to upload an image, set a focal point on the image, and use predefined crops. + +By default, images in the Image Cropper will be shown based on a set focal point and only use specific crops if they are available. + +The Image Cropper comes with 3 modes: + +* Uploading an image +* Setting a focal point +* Cropping the image to predefined crops + +### Uploading images + +The editor exposes a drop area for files. Select it to upload an image. + +![Image Cropper Upload](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/imageCropper-upload-v8.png) + +### Set focal point + +By default, the Image Cropper allows the editor to set a focal point on the uploaded image. + +All the preset crops are shown to give the editor a preview of what the image will look like on the frontend. + +![Image Cropper Focal Point](images/imageCropper-focalpoint.png) + +### Crop and resize + +The editor can fit the crop to the image to ensure that the image is presented as intended. + +![Image Cropper crop](images/imageCropper-crop.png) + +## Powered by ImageSharp.Web + +[ImageSharp.Web](https://sixlabors.com/products/imagesharp-web/) is image processing middleware for ASP.NET. + +We bundle this package with Umbraco and you can therefore take full advantage of all its features for resizing and format changing. Learn more about the built in processing commands in [the official ImageSharp documentation](https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html). + +## Sample code + +The Image Cropper comes with an API to generate crop URLs. You can also access the raw data directly as a dynamic object. + +For rendering a cropped media item, the `.GetCropUrl` is used: + +```html + +``` + +The third parameter is `HtmlEncode` and is by default set to true. This means you only need to define the parameter if you want to disable HTML encoding. + +### Example to output a "banner" crop from a cropper property with the property alias "customCropper" + +```html + +``` + +Or, alternatively using the `MediaWithCrops` extension method: + +```html + +``` + +### Example to dynamically create a crop using the focal point - in this case 300 x 400px image + +```csharp +@if (Model.Photo is not null) +{ + @Model.Photo.Name +} +``` + +### CSS background example to output a "banner" crop + +Set the `htmlEncode` to false so that the URL is not HTML encoded + +```csharp +@if (Model.Photo is not null) +{ + var cropUrl = Url.GetCropUrl(Model.Photo, "square", false); + +
+} +``` + +## Add values programmatically + +To update a content property value you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +The following sample demonstrates how to add or change the value of an Image Cropper property programmatically. The sample creates an API controller with an action, which must be invoked via a POST request to the URL written above the action. + +```csharp +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.ValueConverters; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Docs.Samples.Web.Property_Editors_Add_Values; + +[ApiController] +[Route("/umbraco/api/createimagecroppervalues")] +public class CreateImageCropperValuesController : Controller +{ + private readonly IContentService _contentService; + private readonly IMediaService _mediaService; + private readonly MediaUrlGeneratorCollection _mediaUrlGeneratorCollection; + private readonly IJsonSerializer serializer; + + public CreateImageCropperValuesController( + IContentService contentService, + IMediaService mediaService, + MediaUrlGeneratorCollection mediaUrlGeneratorCollection, IJsonSerializer serializer) + { + _contentService = contentService; + _mediaService = mediaService; + _mediaUrlGeneratorCollection = mediaUrlGeneratorCollection; + this.serializer = serializer; + } + + // /Umbraco/Api/CreateImageCropperValues/CreateImageCropperValues + [HttpPost("createimagecroppervalues")] + public ActionResult CreateImageCropperValues() + { + // Create a variable for the GUID of the page you want to update + var contentKey = Guid.Parse("89974f8b-e213-4c32-9f7a-40522d87aa2f"); + + // Get the page using the GUID you've defined + IContent? content = _contentService.GetById(contentKey); + if (content == null) + { + return false; + } + + // Create a variable for the GUID of the media item you want to use + var mediaKey = Guid.Parse("b6d4e98a-07c0-45f9-bfcc-52994f2806b6"); + + // Get the desired media file + IMedia? media = _mediaService.GetById(mediaKey); + if (media == null) + { + return false; + } + + // Create a variable for the image cropper and set the source + var imageCropperValue = new ImageCropperValue + { + Src = media.GetUrl("umbracoFile", _mediaUrlGeneratorCollection) + }; + + // Serialize the image cropper value + var propertyValue = serializer.Serialize(imageCropperValue); + + // Set the value of the property with alias "cropper" + // - remember to add the "culture" parameter if "cropper" is set to vary by culture + content.SetValue("cropper", propertyValue); + + return _contentService.Save(content).Success; + } +} +``` + +If you use Models Builder to generate source code (modes `SourceCodeAuto` or `SourceCodeManual`), you can use `nameof([generated property name])` to access the desired property without using a magic string: + +```csharp +// Set the value of the "Cropper" property on content of type MyContentType +// - remember to add the "culture" parameter if "cropper" is set to vary by culture +content.SetValue(nameof(MyContentType.Cropper).ToFirstLowerInvariant(), propertyValue); +``` + +## Get all the crop urls for a specific image + +Crop URLs are not limited to usage within a view. `IPublishedContent` has a `GetCropUrl` extension method, which can be used to access crop URLs anywhere. + +The following sample demonstrates how to use `GetCropUrl` to retrieve URLs for all crops defined on a specific image: + +```csharp +public Dictionary GetCropUrls(IPublishedContent image) +{ + // Get the Image Cropper property value for property with alias "umbracoFile" + ImageCropperValue? imageCropperValue = image.Value("umbracoFile"); + if (imageCropperValue?.Crops == null) + { + return new Dictionary(); + } + + // Return all crop aliases and their corresponding crop URLs as a dictionary + var cropUrls = new Dictionary(); + foreach (ImageCropperValue.ImageCropperCrop crop in imageCropperValue.Crops) + { + // Get the cropped URL and add it to the dictionary that I will return + var cropUrl = crop.Alias != null + ? image.GetCropUrl(crop.Alias) + : null; + if (cropUrl != null) + { + cropUrls.Add(crop.Alias!, cropUrl); + } + } + + return cropUrls; +} +``` + +## Sample on how to change the format of the image + +Below the example to output a PNG using ImageSharp.Web [format](https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html#format) command. + +```html + +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Checkbox-Data-Type.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Checkbox-Data-Type.png new file mode 100644 index 00000000000..70eab847d64 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Checkbox-Data-Type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Color-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Color-Picker-DataType.png new file mode 100644 index 00000000000..c6ea4a2cd1f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Color-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Document-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Document-Picker-DataType.png new file mode 100644 index 00000000000..18573dd59d2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Document-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Dropdown-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Dropdown-DataType.png new file mode 100644 index 00000000000..ea1da4a3cfc Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Dropdown-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-Content.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-Content.png new file mode 100644 index 00000000000..d8ce4de3f88 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-Content.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-DataType.png new file mode 100644 index 00000000000..0f1fb36893a Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Eye-Dropper-Color-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Label-Setup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Label-Setup.png new file mode 100644 index 00000000000..11094fa224c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Label-Setup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Markdown-Editor-definition-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Markdown-Editor-definition-example.png new file mode 100644 index 00000000000..0b4b46160d6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Markdown-Editor-definition-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Media-picker-dataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Media-picker-dataType.png new file mode 100644 index 00000000000..0521ffd75db Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Media-picker-dataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/MediaPicker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/MediaPicker-DataType.png new file mode 100644 index 00000000000..bc6ac25056b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/MediaPicker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker-DataType.png new file mode 100644 index 00000000000..a0510029d2f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker.png new file mode 100644 index 00000000000..2f42aa8db1c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Member-Picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Multi-Url-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Multi-Url-Picker-DataType.png new file mode 100644 index 00000000000..63981d74060 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Multi-Url-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/RadioButton-List-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/RadioButton-List-DataType.png new file mode 100644 index 00000000000..ec80c6b02c1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/RadioButton-List-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Repeatable-Textstrings-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Repeatable-Textstrings-DataType.png new file mode 100644 index 00000000000..eda135248f9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Repeatable-Textstrings-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Slider-Data-Type-Definition.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Slider-Data-Type-Definition.png new file mode 100644 index 00000000000..9620542ac7f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Slider-Data-Type-Definition.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textarea-Setup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textarea-Setup.png new file mode 100644 index 00000000000..0373a9f3dec Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textarea-Setup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textbox-Setup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textbox-Setup.png new file mode 100644 index 00000000000..75804945088 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/Textbox-Setup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/User-Picker-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/User-Picker-DataType.png new file mode 100644 index 00000000000..4edc07b73e6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/User-Picker-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/checkbox-list-setup.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/checkbox-list-setup.png new file mode 100644 index 00000000000..798ccd419be Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/checkbox-list-setup.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-column-content-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-column-content-picker.png new file mode 100644 index 00000000000..f0e664a416b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-column-content-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-label-template.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-label-template.png new file mode 100644 index 00000000000..30d0e0033ec Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-label-template.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-property-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-property-picker.png new file mode 100644 index 00000000000..375af70dc02 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-property-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-view-cards-content-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-view-cards-content-picker.png new file mode 100644 index 00000000000..cfb2e51eb9f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collection-view-cards-content-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collections-display-email.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collections-display-email.png new file mode 100644 index 00000000000..d54e5d4a712 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/collections-display-email.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-example.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-example.png new file mode 100644 index 00000000000..98474c05999 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-example.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-picked-value.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-picked-value.png new file mode 100644 index 00000000000..9726d5c05ea Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-picked-value.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-property.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-property.png new file mode 100644 index 00000000000..a20251e8876 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/content-picker-property.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/date-time.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/date-time.png new file mode 100644 index 00000000000..260e07b5791 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/date-time.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/emailaddress-datatype.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/emailaddress-datatype.png new file mode 100644 index 00000000000..6806c536bb2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/emailaddress-datatype.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/enable-listview-v14.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/enable-listview-v14.png new file mode 100644 index 00000000000..f15477d46b6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/enable-listview-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/file-upload-definition.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/file-upload-definition.png new file mode 100644 index 00000000000..8fd78917069 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/file-upload-definition.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-crop.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-crop.png new file mode 100644 index 00000000000..de2e956bea5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-crop.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-focalpoint.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-focalpoint.png new file mode 100644 index 00000000000..8124cc53681 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper-focalpoint.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper.png new file mode 100644 index 00000000000..786888e25e9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/imageCropper.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/list-view-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/list-view-settings.png new file mode 100644 index 00000000000..dad410c9d85 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/list-view-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/listview-v14.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/listview-v14.png new file mode 100644 index 00000000000..63e85069886 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/listview-v14.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/numeric-datatype.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/numeric-datatype.png new file mode 100644 index 00000000000..359e2787a82 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/numeric-datatype.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/tags-DataType.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/tags-DataType.png new file mode 100644 index 00000000000..007770a99a3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/images/tags-DataType.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md new file mode 100644 index 00000000000..d8b2656e1a3 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/label.md @@ -0,0 +1,92 @@ +# Label + +`Schema Alias: Umbraco.Label` + +`UI Alias: Umb.PropertyEditorUi.Label` + +`Returns: String` + +Label is a non-editable control and can only be used to display a pre-set value. + +## Data Type Definition Example + +![Label Data Type definition](images/Label-Setup.png) + +### Value type + +If you want to set a value other than a String, you can define the data using one of the other available Data Types. These include Decimal, Date/time, Time, Integer, and Big integer. + +There is also a Value Type: Long string if you need to set a long string value for your Label. + +## Content Example + +![Label Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Label-Content-v8.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (Model.HasValue("pageLabel")){ +

@(Model.Value("pageLabel"))

+ } +} +``` + +### With Models Builder + +```csharp +@{ + if (!string.IsNullOrEmpty(Model.PageLabel)) + { +

@Model.PageLabel

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'pageLabel'. + content.SetValue("pageLabel", "A pre-set string value"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'pageLabel' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyLabel).Alias, "A pre-set string value"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md new file mode 100644 index 00000000000..7b5fa8f532a --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/markdown-editor.md @@ -0,0 +1,111 @@ +# Markdown Editor + +`Schema Alias: Umbraco.MarkdownEditor` + +`UI Alias: Umb.PropertyEditorUi.MarkdownEditor` + +`Returns: System.Web.HtmlString` + +This built-in editor allow the user to use the markdown formatting options, from within a rich text editor-like interface. + +## Data Type Definition Example + +![Markdown Editor definition example](images/Markdown-Editor-definition-example.png) + +There are three settings available for manipulating the **Markdown editor** property. + +* **Preview** toggles if a preview of the markdown should be displayed beneath the editor in the content view. +* **Default value** is inserted if no content has been saved to the Document Type using this property editor. +* **Overlay Size** is used to select the width of the link picker overlay in the content view. + +## Content Example + +![Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Markdown-Editor-content-example.png) + +### Explanation of buttons from left to right + +| Function | Shortcut | Further explanation | +| --------------------- | -------- | -------------------------------------- | +| toggle **bold** text | Ctrl + B | | +| toggle _italic_ text | Ctrl + I | | +| insert link | Ctrl + L | This opens the Select Link interface. | +| toggle quote | Ctrl + Q | | +| toggle code block | Ctrl + K | | +| insert image | Ctrl + G | This opens the Select Media interface. | +| toggle ordered list | Ctrl + O | | +| toggle unordered list | Ctrl + U | | +| toggle heading | Ctrl + H | This toggles between h1, h2 and off. | +| toggle a hr | | | +| undo | Ctrl + Z | | +| redo | Ctrl + Y | | + +### Other functionality + +| Function | Shortcut | +| ---------- | -------- | +| select all | Ctrl + A | +| copy | Ctrl + C | +| paste | Ctrl + V | + +## MVC View Example + +### With Models Builder + +```csharp +@Model.MyMarkdownEditor +``` + +### Without Models Builder + +```csharp +@Model.Value("MyMarkdownEditor") +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Create markdown value + var markdownValue = new HtmlString("#heading \n**strong text**"); + + // Set the value of the property with alias 'myMarkdownEditor'. + content.SetValue("myMarkdownEditor", markdownValue); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'myMarkdownEditor' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyMarkdownEditor).Alias, markdownValue); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md new file mode 100644 index 00000000000..5114b4f2852 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/media-picker-3.md @@ -0,0 +1,215 @@ +# Media Picker + +`Schema Alias: Umbraco.MediaPicker3` + +`UI Alias: Umb.PropertyEditorUi.MediaPicker` + +`Returns: IEnumerable` or `MediaWithCrops` + +This property editors returns one of the following: + +- A collection (`IEnumerable`) if the **Pick multiple items** setting is enabled. +- A single `MediaWithCrops` item if the **Pick multiple items** setting is disabled. + +## Data Type Definition Example + +![Media Picker Data Type Definition](images/MediaPicker-DataType.png) + +### Accepted types + +Use setting to limit the picker to only select Media Items of these types. + +### Pick multiple items + +Use this setting to enable the property to contain multiple items. When this is enabled the property editor returns an `IEnumerable`. + +You can still set the maximum amount to 1. Do so when you want to retrieve a collection but only allow the Content Editors to select one Media Item. + +### Amount + +Use this setting to enforce a minimum and/or maximum amount of selected Media Items. + +{% hint style="info" %} +It is not possible to set a maximum amount when the "Pick multiple items" feature is disabled. +{% endhint %} + +### Start node + +This setting is used to limit the Media Picker to certain parts of the Media Tree. + +### Ignore user start nodes + +Use this setting to overrule user permissions, to enable any user of this property to pick any Media Item of the chosen Start node. + +When this setting is enabled, a user can access the media available under the selected "Start Node" (/Design in this case). This applies even if they normally lack access. The access is granted specifically when using this particular Media Picker. + +### Enable Focal Point + +Enable the focal point setter, do only enable this if the focal point is used or if you have Image crops defined. + +### Image Crops + +Define local image crops. Local image crop data is stored on the document in this property. This means it can differentiate between documents. + +This is different from Global crops as they are defined on the Media Item, making the crops shared between all usage of that Media Item. + +Global crops are configured on the Image Cropper property of the Image Media Type + +[Read about the Image Cropper here](image-cropper.md) + +## Content Example + +![Media Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Media-Picker3-Content.jpg) + +## MVC View Example + +### Multiple enabled without Models Builder + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var typedMultiMediaPicker = Model.Value>("medias"); + foreach (var entry in typedMultiMediaPicker) + { + + } +} +``` + +#### Multiple enabled without Models Builder to retrieve IEnumerable data + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var listOfImages = Model.Value>("medias"); + foreach (var image in listOfImages) + { + @image.Name + } +} +``` + +{% hint style="info" %} +While `MediaWithCrops` is the default return type, `IPublishedContent` may be used in backward-compatible implementations or when working directly with core APIs. +{% endhint %} + +### Multiple enabled with Models Builder + +```csharp +@{ + var typedMultiMediaPicker = Model.Medias; + foreach (var entry in typedMultiMediaPicker) + { + + } +} +``` + +### Multiple disabled without Models Builder + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var typedMediaPickerSingle = Model.Value("media"); + if (typedMediaPickerSingle != null) + { + @typedMediaPickerSingle.Value( + } +} +``` + +### Multiple disabled with Models Builder + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var typedMediaPickerSingle = Model.Media; + if (typedMediaPickerSingle is MediaWithCrops mediaEntry) + { + + } +} +``` + +## Using crops + +Both local and global crops are retrieved using the method `GetCropUrl`. If crops with identical aliases are defined both locally and globally, the locally defined crops are always prioritized by `GetCropUrl`. + +The following is an example of how to retrieve a crop from a `MediaWithCrops` entry: + +```csharp +@{ + foreach (var entry in Model.Medias) + { + + } +} +``` + +### Explicitly retrieving global crops + +You can retrieve globally defined crops explicitly by using `GetCropUrl` on the `UrlHelper`: + +```csharp +@{ + foreach (var entry in Model.Medias) + { + + } +} +``` + +### Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +The following sample will update a single image in a Media Picker. + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Get the media you want to assign to the media picker + var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8"); + + // Create an Udi of the media + var udi = Udi.Create(Constants.UdiEntityType.Media, media.Key); + + // Set the value of the property with alias 'featuredBanner'. + content.SetValue("featuredBanner", udi.ToString()); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'featuredBanner' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FeaturedBanner).Alias, udi.ToString()); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md new file mode 100644 index 00000000000..234645e6e4a --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-group-picker.md @@ -0,0 +1,93 @@ +# Member Group Picker + +`Schema Alias: Umbraco.MemberGroupPicker` + +`UI Alias: Umb.PropertyEditorUi.MemberGroupPicker` + +`Returns: string` + +The Member Group Picker opens a panel to pick one or more member groups from the Member section. The value saved is of type string (comma separated IDs). + +## Data Type Definition Example + +![Member Group Picker Type Definition](images/Member-Picker-DataType.png) + +## Content Example + +![Member Grouep Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Group-Picker-Content.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@if (Model.HasValue("memberGroup")) +{ + var memberGroup = Model.Value("memberGroup"); +

@memberGroup

+} +``` + +### With Models Builder + +```csharp +@if (!string.IsNullOrEmpty(Model.MemberGroup)) +{ +

@Model.MemberGroup

+} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'memberGroup'. The value is the specific ID of the member group + content.SetValue("memberGroup", 1067); + + // Save the change + ContentService.Save(content); +} +``` + +You can also add multiple groups by creating a comma separated string with the desired member group IDs. + +```csharp +@{ + // Set the value of the property with alias 'memberGroup'. + content.SetValue("memberGroup", "1067","1068"); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'memberGroup' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MemberGroup).Alias, 1067); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md new file mode 100644 index 00000000000..bbe672ae2fe --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/member-picker.md @@ -0,0 +1,92 @@ +# Member Picker + +`Schema Alias: Umbraco.MemberPicker` + +`UI Alias: Umb.PropertyEditorUi.MemberPicker` + +`Returns: IPublishedContent` + +The member picker opens a panel to pick a specific member from the member section. The value saved is of type IPublishedContent. + +## Data Type Definition Example + +![Media Picker Data Type Definition](images/Member-Picker.png) + +## Content Example + +![Member Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Member-Picker-Content-v8.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (Model.HasValue("author")) + { + var member = Model.Value("author"); + @member.Name + } +} +``` + +### With Models Builder + +```csharp +@{ + if (Model.Author != null) + { + var member = Model.Author; + @member.Name + } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Create a variable for the GUID of the member ID + var authorId = Guid.Parse("ed944097281e4492bcdf783355219450"); + + // Set the value of the property with alias 'author'. + content.SetValue("author", authorId); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'author' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Author).Alias, udi); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md new file mode 100644 index 00000000000..ed6d10a7330 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multi-url-picker.md @@ -0,0 +1,147 @@ +# Multi Url Picker + +`Schema Alias: Umbraco.MultiUrlPicker` + +`UI Alias: Umb.PropertyEditorUi.MultiUrlPicker` + +`Returns: IEnumerable or Link` + +Multi Url Picker allows an editor to pick and sort multiple urls. This property editor returns a single item if the "Maximum number of items" Data Type setting is set to 1 or a collection if it is 0. These can either be internal, external or media. + +## Data Type Definition Example + +![Related Links Data Type Definition](images/Multi-Url-Picker-DataType.png) + +## Content Example + +![Media Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multy-Url-Picker-Content-v8.png) + +## MVC View Example - value converters enabled + +## Typed + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var links = Model.Value>("footerLinks"); + if (links.Any()) + { +
    + @foreach (var link in links) + { +
  • @link.Name
  • + } +
+ } +} +``` + +If `Max number of items` is configured to `1` + +```csharp +@using Umbraco.Cms.Core.Models +@{ + var link = Model.Value("link"); + if (link != null) + { + @link.Name + } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core +@using Umbraco.Cms.Core.Serialization +@using Umbraco.Cms.Core.Services +@using Umbraco.Cms.Core.Models +@inject IContentService ContentService +@inject IJsonSerializer Serializer +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Get the media you want to assign to the footer links property + var media = Umbraco.Media("bca8d5fa-de0a-4f2b-9520-02118d8329a8"); + + // Create an Udi of the media + var mediaUdi = Udi.Create(Constants.UdiEntityType.Media, media.Key); + + // Get the content you want to assign to the footer links property + var contentPage = Umbraco.Content("665d7368-e43e-4a83-b1d4-43853860dc45"); + + // Create an Udi of the Content + var contentPageUdi = Udi.Create(Constants.UdiEntityType.Document, contentPage.Key); + + // Create a list with different link types + var externalLinks = new List + { + // External Link + new Link + { + Target = "_blank", + Name = "Our Umbraco", + Url = "https://our.umbraco.com/", + Type = LinkType.External + }, + // Media + new Link + { + Target = "_self", + Name = media.Name, + Url = media.MediaUrl(), + Type = LinkType.Media, + Udi = mediaUdi + }, + // Content + new Link + { + Target = "_self", + Name = contentPage.Name, + Url = contentPage.Url(), + Type = LinkType.Content, + Udi = contentPageUdi + } + }; + + // Serialize the list with links to JSON + var links = Serializer.Serialize(externalLinks); + + + // Set the value of the property with alias 'footerLinks'. + content.SetValue("footerLinks", links); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'footerLinks' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.FooterLinks).Alias, links); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md new file mode 100644 index 00000000000..71db7e81462 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multiple-textbox.md @@ -0,0 +1,101 @@ +# Repeatable Textstrings + +`Schema Alias: Umbraco.MultipleTextstring` + +`UI Alias: Umb.PropertyEditorUi.MultipleTextString` + +`Returns: array of strings` + +The Repeatable textstrings property editor enables a content editor to make a list of text items. For best use with an unordered-list. + +## Data Type Definition Example + +![Repeatable textstrings Data Type Definition](images/Repeatable-Textstrings-DataType.png) + +## Content Example + +![Repeatable textstrings Content](<../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Multiple-Textbox-Repeatable-Textstrings-Content (1) (1).png>) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (Model.Value("keyFeatureList").Length > 0) + { +
    + @foreach (var item in Model.Value("keyFeatureList")) + { +
  • @item
  • + } +
+ } +} +``` + +### With Models Builder + +```csharp +@{ + if (Model.KeyFeatureList.Any()) + { +
    + @foreach (var item in Model.KeyFeatureList) + { +
  • @item
  • + } +
+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'keyFeatureList' + content.SetValue("keyFeatureList", "Awesome" + Environment.NewLine + "Super"); + + // Save the change + ContentService.Save(content); +} +``` + +{% hint style="info" %} +To add multiple values to the repeatable text strings property editor you have to put each value on a new line. This can be achieved using either `\r\n\` or `Environment.NewLine`. +{% endhint %} + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'keyFeatureList' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.KeyFeatureList).Alias, "Awesome" + Environment.NewLine + "Super"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md new file mode 100644 index 00000000000..facbede1337 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/numeric.md @@ -0,0 +1,118 @@ +# Numeric + +`Schema Alias: Umbraco.Integer` + +`UI Alias: Umb.PropertyEditorUi.Integer` + +`Returns: Integer` + +Numeric is an HTML input control for entering numbers. Since it's a standard HTML element the options and behaviour are all controlled by the browser and therefore is beyond the control of Umbraco. + +## Data Type Definition Example + +![Numeric Data Type Definition](images/numeric-datatype.png) + +### Minimum + +This allows you to set up a minimum value. If you will always need a minimum value of 10 this is where you set it up and whenever you use the datatype the value will always start at 10. It's not possible to change the value to anything lower than 10. Only higher values will be accepted. + +### Step Size + +This allows you to control by how much value should be allowed to increase/decrease when clicking the up/down arrows. If you try to enter a value that does not match with the step setting then it will not be accepted. + +### Maximum + +This allows you to set up a maximum value. If you will always need a maximum value of 100 this is where you set it up. It's not possible to change the value to anything higher than 100. Only lower values will be accepted. + +## Settings + +## Content Example + +![Numeric Content Definition](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/numeric-content.png) + +## MVC View Examples + +### Rendering the output casting to an int (without Models Builder) + +By casting the output as an int it's possible for you to do mathematical operations with the value. + +```csharp +@{ + int students = Model.HasValue("students") ? Model.Value("students") : 0; + int teachers = Model.HasValue("teachers") ? Model.Value("teachers") : 0; + int totalTravellers = students + teachers; + +

@totalTravellers

+} +``` + +### Rendering the output casting to a string (Without Models Builder) + +You can also render the output by casting it to a string, which means you will not be able to do mathematical operations + +```csharp +@{ + if(Model.HasValue("students")){ +

@(Model.Value("students"))

+ } +} +``` + +### With Models Builder + +```csharp +@{ + int students = Model.Students; + int teachers = Model.Teachers; + int totalTravellers = students + teachers; + +

@totalTravellers

+} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'students' + content.SetValue("students", 20); + + // Save the change + ContentService.Save(content); + +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'students' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Students).Alias, 20); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md new file mode 100644 index 00000000000..21d866cc414 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/radiobutton-list.md @@ -0,0 +1,95 @@ +# Radiobutton List + +`Schema Alias: Umbraco.RadioButtonList` + +`UI Alias: Umb.PropertyEditorUi.RadioButtonList` + +`Returns: string` + +Pretty much like the name indicates this Data type enables editors to choose from list of radio buttons and returns the value of the selected item as string. + +## Data Type Definition Example + +![Radiobutton List Data Type Definition](images/RadioButton-List-DataType.png) + +{% hint style="info" %} +You can use dictionary items to translate the values of a Radiobutton List property editor in a multilingual setup. For more details, see the [Creating a Multilingual Site](../../../../tutorials/multilanguage-setup.md#translating-multi-value-property-editors) article. +{% endhint %} + +## Content Example + +![Radiobutton List Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/RadioButton-List-Content-v8.png) + +## MVC View Example + +### Typed + +#### Without Models Builder + +{% code caption="HomePageTemplate.cs" %} + +```csharp +@if (Model.HasValue("colorTheme")) +{ + var value = Model.Value("colorTheme"); +

@value

+} +``` + +{% endcode %} + +#### With Models Builder + +```csharp +@if (Model.ColorTheme != null) +{ + var value = Model.ColorTheme; +

@value

+} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'colorTheme' + content.SetValue("colorTheme", "water"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'colorTheme' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.ColorTheme).Alias, "water"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md new file mode 100644 index 00000000000..50563f97834 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md @@ -0,0 +1,113 @@ +# Rich Text Editor + +`Schema Alias: Umbraco.RichText` + +`UI Alias: Umb.PropertyEditorUi.Tiptap` + +`Returns: HTML` + +{% hint style="warning" %} +With the release of Umbraco 16, [the TinyMCE UI option for the Rich Text Editor is removed](../../../../setup/upgrading/version-specific/#breaking-changes). +{% endhint %} + +The Rich Text Editor property editor is highly configurable and based on [Tiptap](https://tiptap.dev/). Depending on the configuration setup, it provides editors a lot of flexibility when working with content. + +## [Configuration options](configuration.md) + +Customize everything from toolbar options to editor size to where pasted images are saved. + +## [Style Menu](style-menu.md) + +Define a cascading text formatting and style menu for the Rich Text Editor toolbar. + +## [Blocks](blocks.md) + +Use Blocks to define specific parts that can be added as part of the markup of the Rich Text Editor. + +## [Extensions](extensions.md) + +Extend the functionality of the Rich Text Editor with extensions. + +## [Custom CSS properties](css-properties.md) + +Customize the appearance of the Rich Text Editor with custom CSS properties. + +## Data Type Definition Example + +![Rich Text Editor - Data Type](images/rte-tiptap-datatypedefinition.png) + +## Content Example + +![Rich Text Editor - Content Example](images/rte-tiptap-contentexample.png) + +## MVC View Example + +### With Models Builder + +```csharp +@{ + if (!string.IsNullOrEmpty(Model.RichText.ToString())) + { +

@Model.RichText

+ } +} +``` + +### Without Models Builder + +```csharp +@{ + if (Model.HasValue("richText")){ +

@(Model.Value("richText"))

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Create a variable for the desired value + var htmlValue = new HtmlString("Add some text here"); + + // Set the value of the property with alias 'richText'. + content.SetValue("richText", htmlValue); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string. + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'richText' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.RichText).Alias, htmlValue); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md new file mode 100644 index 00000000000..c32644a7b6f --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md @@ -0,0 +1,217 @@ +# Blocks + +Blocks enable editors to insert structured content elements directly into the Rich Text Editor (RTE). Blocks are [Element Types](../../../../data/defining-content/default-document-types.md#element-type) and can be configured with custom properties, styling, and behavior. + +Blocks can be added to the Rich Text Editor when: + +* Available Blocks are specified as part of the Rich Text Editor Data Type configuration. +* The **Insert Block** toolbar option is enabled in the Rich Text Editor. + +![RTE Insert Block Toolbar Button](images/rte-blocks-toolbar-insert-button.png) + +## Configure Blocks + +Blocks are Element Types that must be created before configuring them as blocks in the Rich Text Editor. You can create Element Types in the **Settings** > **Document Types** section + +Blocks functionality can then be configured through the Rich Text Editor Data Type configuration as follows. + +1. Navigate to **Settings** > **Data Types**. +2. Select your Rich Text Editor Data Type or create a new one. +3. Locate the **Available Blocks** section. +4. Add the Element Types you want to make available as blocks. +5. Configure each Block Type with the options described below. + +![RTE Blocks Data Type Configuration](images/rte-blocks-datatype-configuration.png) + +### Editor Appearance + +Configure how blocks appear and behave in the Content section: + +* **Label** - Define how the block appears in the editor. Umbraco 16 uses [Umbraco Flavoured Markdown](../../../../../reference/umbraco-flavored-markdown.md) (UFM) syntax for dynamic labels. Use `{=propertyAlias}` to display property values (e.g., `{=author}` for a text property containing the name of an author, or `Written by: {=author}` for a label with static text and dynamic content). +* **Display Inline** - When enabled, blocks remain inline with surrounding text. When disabled, blocks appear on separate lines. +* **Overlay size** - Set the size of the editing overlay when editors work with the block content. + +![RTE Blocks Editor Appearance Settings](images/rte-blocks-editor-appearance-settings.png) + +### Data Models + +Configure the content structure for your blocks: + +* **Content model** - The Element Type that defines the main content properties for the block (required). +* **Settings model** - Optional Element Type that defines additional settings or configuration options for the block. + +![RTE Blocks Data Models Settings](images/rte-blocks-data-models-settings.png) + +### Catalogue Appearance + +Control how blocks appear in the block picker: + +* **Background color** - Background color displayed behind the block icon or thumbnail. +* **Icon Color** - Color of the Element Type icon. +* **Thumbnail** - Custom image to replace the default Element Type icon. + +## Working with Blocks + +### Adding Blocks to Content + +Editors can add blocks to rich text content using the **Insert Block** toolbar button: + +1. Position the cursor where you want to insert the block + +2. Click the **Insert Block** button in the Rich Text Editor toolbar + + ![Adding Blocks to Content - Step 1](images/rte-blocks-adding-to-content-1.png) + +3. Select the desired Block from the available options + + ![Adding Blocks to Content - Step 2](images/rte-blocks-adding-to-content-2.png) + +4. Configure the block content (and settings, if provided) + + ![Adding Blocks to Content - Step 3](images/rte-blocks-adding-to-content-3.png) + +The block appears in the editor as a structured element. + +## Rendering Blocks + +To display blocks on the frontend, create Partial Views for each Block. + +{% hint style="info" %} +Rich Text Editor blocks use a different view location than Block List blocks. RTE blocks are placed in `Views/Partials/RichText/Components/`, while Block List blocks use `Views/Partials/BlockList/Components/`. +{% endhint %} + +### File Structure + +* **Location**: `Views/Partials/RichText/Components/`. +* **Naming**: Use the exact Element Type alias as the filename (e.g., `quoteBlock.cshtml` for alias `quoteBlock`). +* **Model**: `Umbraco.Cms.Core.Models.Blocks.RichTextBlockItem`. + +The different folder structure ensures that RTE blocks and Block List blocks can have separate rendering implementations, even when using the same Element Types. + +{% hint style="warning" %} +The view filename must match the Element Type alias exactly. If you see the error `ArgumentException: ~/Views/Partials/richtext/Components/[filename].cshtml does not match any available view`, verify that your view filename matches your Element Type alias precisely. +{% endhint %} + +### Example Partial View + +For a Block Type with Element Type alias `quoteBlock`: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage + +@{ + var quoteText = Model.Content.Value("quoteText")?.ToString(); + var citation = Model.Content.Value("citation")?.ToString(); +} + +
+ @if (!string.IsNullOrEmpty(quoteText)) + { +

@Html.Raw(quoteText)

+ } + + @if (!string.IsNullOrEmpty(citation)) + { + @citation + } +
+``` + +### Example with Settings Model + +For a Call To Action block with Element Type alias `callToActionBlock` and settings model `callToActionBlockSettings`: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using Umbraco.Cms.Core.Models + +@{ + // Get link from Multi URL Picker + var linkPicker = Model.Content.Value>("link"); + var link = linkPicker?.FirstOrDefault(); + + // Get style from settings (if settings model exists) + var style = "primary"; // Default style + if (Model.Settings != null) + { + var settingsStyle = Model.Settings.Value("style")?.ToString(); + if (!string.IsNullOrEmpty(settingsStyle)) + { + style = settingsStyle.ToLower(); + } + } + + // CSS class based on style setting + var cssClass = $"cta-button cta-button--{style}"; +} + +@if (link != null && !string.IsNullOrEmpty(link.Url)) +{ + +} +``` + +### Type-Safe Rendering with Models Builder + +When using Models Builder, specify the Content and Settings models for type-safe access: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage> +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; + +@{ + var style = ""; + if (Model.Settings?.Color != null) + { + style = $"style=\"border-left-color: {Model.Settings.Color};\""; + } +} + +
+ @if (!string.IsNullOrEmpty(Model.Content.QuoteText)) + { +

@Html.Raw(Model.Content.QuoteText)

+ } + + @if (!string.IsNullOrEmpty(Model.Content.Citation)) + { + @Model.Content.Citation + } +
+``` + +## Build a Custom Backoffice View + +Building Custom Views for Block representations in Backoffice is the same for all Block Editors. [Read about building a Custom View for Blocks here](../../../../../tutorials/creating-custom-views-for-blocklist.md). + +## Best Practices + +### Content Design + +* Design blocks for reusable content patterns. +* Keep block content focused on a single purpose. +* Use descriptive labels that help editors understand the block's function. + +### Performance + +* Avoid creating too many Blocks - this can overwhelm content editors. +* Use appropriate caching strategies for block rendering. +* Consider the impact of complex blocks on editor performance. + +### Accessibility + +* Ensure block markup follows accessibility guidelines. +* Provide meaningful labels and descriptions. +* Test block rendering with screen readers. + +## Related Articles + +* [Element Types](../../../../data/defining-content/default-document-types.md#element-type) +* [Rich Text Editor Configuration](configuration.md) +* [Rich Text Editor Extensions](extensions.md) diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md new file mode 100644 index 00000000000..48405ffe71d --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/configuration.md @@ -0,0 +1,58 @@ +# Configuration + +In this article you can learn about the different options you have for configuring the Rich Text Editor (RTE). + +## Toolbar + +You have full control over which options should be available on the RTE. + +![Toolbar: All options enabled](images/rte-tiptap-all-toolbar-items.png) + +In the example above, all 38 options have been enabled. These options include font styles like bold and italics, bullet lists, and options to embed videos and insert images. + +You can customize the look of the toolbar: + +* Enhance the capabilities of the toolbar by enabling or disabling extensions. +* Use the Toolbar designer to group together items and add additional rows if needed. + +![Enhance and customize the capabilities of the Rich Text Editor toolbar](images/rte-tiptap-capabilities-and-toolbar.png) + +## Statusbar + +As well as the toolbar, you can configure extensions for the statusbar. + +![Statusbar with Word Count extension enabled](images/rte-tiptap-statusbar.png) + +## Stylesheets + +To apply custom styles to the Rich Text Editor, you can select from any existing stylesheets. + +Stylesheets can be created in the **Settings** section. To learn more about this feature, see the [Stylesheets in the Backoffice](../../../../design/stylesheets-javascript.md) article. + +## Dimensions + +Define `height` and `width` of the editor displayed in the content section. + +## Maximum size for inserted images + +Define the maximum size for images added through the Rich Text Editor. + +If inserted images are larger than the dimensions defined here, the images will be resized automatically. + +## Overlay Size + +Select the width of the link picker overlay. The overlay size comes in three sizes: Small, Medium, Large, and Full. + +## Available Blocks + +Blocks can be added as elements in the Rich Text Editor. Configuration and rendering of Blocks are described in the [Blocks in Rich Text Editor](blocks.md) article. + +## Image Upload Folder + +Images added through the RTE are by default added to the root of the Media library. + +Sometimes you might want to add the images to a specific folder. This folder can be configured using the "Image Upload Folder" setting. + +## Ignore User Start Nodes + +Some of the backoffice users might be restricted to a specific part of the content tree. When the "Ignore User Start Nodes" is checked, the users can pick any piece of content from the content tree, when adding internal links through the RTE. diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/css-properties.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/css-properties.md new file mode 100644 index 00000000000..ab02849b429 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/css-properties.md @@ -0,0 +1,35 @@ +# Custom CSS properties + +Customize the appearance of the Rich Text Editor with custom CSS properties. + +You can customize the appearance of the Rich Text Editor using CSS properties by defining them in your CSS files. + +For example, to set the minimum height of all Rich Text Editors throughout the backoffice. You could use the following CSS rule: + +```css +:root { + --umb-rte-min-height: 300px; +} +``` + +For general information on working with stylesheets and JavaScript in Umbraco, check [Stylesheets and JavaScript](../../../../design/stylesheets-javascript.md). + +If you wanted to target a specific Rich Text Editor, you can set the [stylesheet directly in the configuration](configuration.md#stylesheets). + + +## Custom CSS properties reference + +The following CSS properties are available for customization: + +| CSS Property | Description | Default Value | +| ---------------------- | ------------------------------------------ | ------------- | +| `--umb-rte-width` | The width of the rich-text-editor | `unset` | +| `--umb-rte-min-width` | The minimum width of the rich-text-editor | `unset` | +| `--umb-rte-max-width` | The maximum width of the rich-text-editor | `100%` | +| `--umb-rte-height` | The height of the rich-text-editor | `100%` | +| `--umb-rte-min-height` | The minimum height of the rich-text-editor | `100%` | +| `--umb-rte-max-height` | The maximum height of the rich-text-editor | `100%` | + + +The CSS custom properties may change in future versions of Umbraco. You can always find the latest values in the [Rich Text Editor component base class](https://github.com/umbraco/Umbraco-CMS/blob/main/src/Umbraco.Web.UI.Client/src/packages/rte/components/rte-base.element.ts) in the Umbraco CMS GitHub repository. + diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md new file mode 100644 index 00000000000..eb9bc6980aa --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/extensions.md @@ -0,0 +1,98 @@ +--- +description: Information on how to work with Tiptap extensions in the rich text editor. +--- + +# Extensions + +The Rich Text Editor (RTE) in Umbraco is based on the open-source editor [Tiptap](https://tiptap.dev/). + +Out of the box, Tiptap has limited capabilities and everything is an extension by design. Basic text formatting features such as bold, italic, and underline are their own extensions. This offers great flexibility, making the rich text editor highly configurable. The implementation in Umbraco offers a wide range of built-in extensions to enhance the Tiptap editor capabilities. + +Using the same extension points, this article will show you how to add a custom extension to the rich text editor. + +## Native Tiptap extensions + +Tiptap has a library of supported native extensions. You can find a list of these extensions on the [Tiptap website](https://tiptap.dev/docs/editor/extensions/overview). While many of these are open source, there are also [pro extensions](https://tiptap.dev/docs/guides/pro-extensions) available for commercial subscriptions. + +### Tiptap extension types + +There are two types of extension: `tiptapExtension` and `tiptapToolbarExtension`. + +The `tiptapExtension` extension is used to register a native [Tiptap Extension](https://tiptap.dev/docs/editor/extensions/). These will enhance the capabilities of the rich text editor itself. For example, to enable text formatting, drag-and-drop functionality and spell-checking. + +The `tiptapToolbarExtension` extension adds a toolbar action that interacts with the Tiptap editor (and native Tiptap extensions). + +## Adding a native extension + +{% hint style="info" %} +This example assumes that you will be creating an Umbraco package using the Vite/Lit/TypeScript setup.\ +You can learn how to do this [Vite Package Setup](../../../../../customizing/development-flow/vite-package-setup.md) article. +{% endhint %} + +In this example, you will take the native Tiptap open-source extension [Highlight](https://tiptap.dev/docs/editor/extensions/marks/highlight). Then register it with the rich text editor and add a toolbar button to invoke the Task List action. + +1. Install the Highlight extension from the npm registry. + +``` +npm install @tiptap/extension-highlight +``` + +2. Create the code to register the native Tiptap extensions in the rich text editor. + +```js +import { UmbTiptapExtensionApiBase } from '@umbraco-cms/backoffice/tiptap'; +import { Highlight } from '@tiptap/extension-highlight'; + +export default class UmbTiptapHighlightExtensionApi extends UmbTiptapExtensionApiBase { + getTiptapExtensions = () => [Highlight]; +} +``` + +3. Create the toolbar action to invoke the Highlight extension. + +```js +import { UmbTiptapToolbarElementApiBase } from '@umbraco-cms/backoffice/tiptap'; +import type { Editor } from '@umbraco-cms/backoffice/external/tiptap'; + +export default class UmbTiptapToolbarHighlightExtensionApi extends UmbTiptapToolbarElementApiBase { + override execute(editor?: Editor) { + editor?.chain().focus().toggleHighlight().run(); + } +} +``` + +Once you have the above code in place, they can be referenced using a [bundle extension type](../../../../../customizing/extending-overview/extension-types/bundle.md). + +{% code title="manifests.ts" lineNumbers="true" %} +```js +export const manifests: Array = [ + { + type: 'tiptapExtension', + kind: 'button', + alias: 'My Highlight Tiptap Extension', + name: 'My.Tiptap.Highlight', + api: () => import('./highlight.tiptap-api.js'), + meta:{ + icon: "icon-thumbnail-list", + label: "Highlight", + group: "#tiptap_extGroup_formatting" + } + }, + { + type: 'tiptapToolbarExtension', + kind: 'button', + alias: 'My.Tiptap.Toolbar.Highlight', + name: 'My Highlight Tiptap Toolbar Extension', + js: () => import('./highlight.tiptap-toolbar-api.js'), + forExtensions: ["My.Tiptap.Highlight"], + meta:{ + alias: "highlight", + icon: "icon-brush", + label: "Highlight" + } + } +] +``` +{% endcode %} + +Upon restarting Umbraco, the new extension and toolbar action will be available in the Tiptap Data Type configuration settings. diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/adding-style-select-to-toolbar.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/adding-style-select-to-toolbar.png new file mode 100644 index 00000000000..546ec7c47ba Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/adding-style-select-to-toolbar.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-1.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-1.png new file mode 100644 index 00000000000..47ff9a7eb13 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-1.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-2.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-2.png new file mode 100644 index 00000000000..9294e8bed0c Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-2.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-3.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-3.png new file mode 100644 index 00000000000..a204f47163d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-adding-to-content-3.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-data-models-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-data-models-settings.png new file mode 100644 index 00000000000..f85d58fa82b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-data-models-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-datatype-configuration.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-datatype-configuration.png new file mode 100644 index 00000000000..6aa7845022f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-datatype-configuration.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-editor-appearance-settings.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-editor-appearance-settings.png new file mode 100644 index 00000000000..9e5ebcc88e5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-editor-appearance-settings.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-toolbar-insert-button.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-toolbar-insert-button.png new file mode 100644 index 00000000000..3339e299477 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-blocks-toolbar-insert-button.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-fields.jpg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-fields.jpg new file mode 100644 index 00000000000..ed0ed6da5d4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-fields.jpg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-type-editor.jpeg b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-type-editor.jpeg new file mode 100644 index 00000000000..dd54171ac52 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-data-type-block-type-editor.jpeg differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-change-property.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-change-property.png new file mode 100644 index 00000000000..5916b405fb9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-change-property.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-new-data-type.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-new-data-type.png new file mode 100644 index 00000000000..0d5c77819f4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-new-data-type.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-search-and-find-new-ui.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-search-and-find-new-ui.png new file mode 100644 index 00000000000..f0cc5f36c26 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-search-and-find-new-ui.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-select-ui.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-select-ui.png new file mode 100644 index 00000000000..a067f1928be Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-swap-select-ui.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-all-toolbar-items.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-all-toolbar-items.png new file mode 100644 index 00000000000..b82806c78ea Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-all-toolbar-items.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-capabilities-and-toolbar.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-capabilities-and-toolbar.png new file mode 100644 index 00000000000..1b348a9347d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-capabilities-and-toolbar.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-contentexample.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-contentexample.png new file mode 100644 index 00000000000..caed9635fec Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-contentexample.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-datatypedefinition.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-datatypedefinition.png new file mode 100644 index 00000000000..827504d26e9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-datatypedefinition.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-statusbar.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-statusbar.png new file mode 100644 index 00000000000..f05ec89ee05 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-statusbar.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-stylemenu.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-stylemenu.png new file mode 100644 index 00000000000..792805a78e8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/images/rte-tiptap-stylemenu.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/style-menu.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/style-menu.md new file mode 100644 index 00000000000..5534053968d --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/style-menu.md @@ -0,0 +1,125 @@ +# Style Select Menu + +A Style Select Menu is a configurable extension that adds a cascading menu to the toolbar for applying text styles and formatting. + +![Rich Text Editor cascading style menu](images/rte-tiptap-stylemenu.png) + +{% hint style="info" %} +Any custom stylesheets associated with the Rich Text Editor will not auto generate a style select menu in the toolbar. +{% endhint %} + +## Adding Style Select to Rich Text Editor + +To add Style Select to the Rich Text Editor: + +1. Go to **Settings**. +2. Navigate to **Data Types**. +3. Select the relevant Data Type. +4. Drag **Style Select** from **Available Actions** into the **Toolbar** section. +5. Click **Save**. + +Alternatively, while configuring an editor on a Document Type, you can drag **Style Select** from **Available Actions** into the **Toolbar** section. + +![Adding Style Select to the Rich Text Editor](images/adding-style-select-to-toolbar.png) + +## Creating a Style Select Menu + +In this article, you can find an example of how to set up a Style Select Menu using the package manifest file. + +{% code title="umbraco-package.json" %} +```json +{ + "name": "Name of your package", + "alias": "My.Package", + "extensions": [ + { + "type": "tiptapToolbarExtension", + "kind": "styleMenu", + "alias": "MyCustom.Tiptap.StyleMenu", + "name": "My Custom Tiptap Style Menu", + "meta": { + "alias": "myCustomStyleMenu", + "icon": "icon-palette", + "label": "My custom styles" + }, + "items": [ + { + "label": "Headings", + "items": [ + { + "label": "Heading 2", + "data": { "tag": "h2" }, + "appearance": { "icon": "icon-heading-2" } + }, + { + "label": "Heading 3", + "data": { "tag": "h3" }, + "appearance": { "style": "font-size: large;" } + }, + { + "label": "Heading 4", + "data": { "tag": "h4" } + } + ] + }, + { + "label": "Attributes", + "items": [ + { + "label": "Classes", + "data": { "class": "foo" } + }, + { + "label": "IDs", + "data": { "id": "bar" } + }, + { + "label": "Mixed", + "data": { "tag": "span", "class": "foo", "id": "bar" } + } + ] + } + ] + } + ] +} +``` +{% endcode %} + +The `items` property defines the structure of the style select menu. Each menu item has the following options: + +- `label`: _(required)_ The label of the menu item. This supports localization keys. +- `appearance`: This defines the appearance of the menu item. The value has 2 optional properties: + - `icon`: To prefix an icon to the menu item. + - `style`: To apply CSS rules to the menu item. +- `data`: To configure the function of the style select menu item. The value has 3 optional properties: + - `tag`: A [supported HTML tag](#supported-html-tags) name. This will be applied to the selected text. + - `class`: Applies a class attribute with the defined class name to the containing tag of the selected text. + - `id`: Applies an ID attribute with the defined ID value to the containing tag of the selected text. +- `separatorAfter`: When `true`, it will add a line separator after the menu item. +- `items`: To enable a cascading menu, an array of nested menu items may be added. + +Once configured, all custom style select menus will appear in the Rich Text Editor toolbar options, as described in the [Rich Text Editor Configuration](configuration.md) article. + +### Supported HTML tags + +Due to Tiptap’s strict rich-text schema, only supported HTML tags are allowed in the style select menu, _(arbitrary markup will be excluded)._ The following HTML tag names are supported: + +- `h1` +- `h2` +- `h3` +- `h4` +- `h5` +- `h6` +- `p` +- `blockquote` +- `code` +- `codeBlock` +- `div` +- `em` (italic) +- `ol` +- `strong` (bold) +- `s` (strike-through) +- `span` +- `u` (underline) +- `ul` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/slider.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/slider.md new file mode 100644 index 00000000000..46c977ec3f6 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/slider.md @@ -0,0 +1,133 @@ +# Slider + +`Schema Alias: Umbraco.Slider` + +`UI Alias: Umb.PropertyEditorUi.Slider` + +`Returns: decimal` or `Umbraco.Core.Models.Range` + +Pretty much like the name indicates this Data type enables editors to choose a value with a range using a slider. + +There are two flavors of the slider. One with a single value picker. One with a minimum and maximum value. + +## Data Type Definition Example + +![Slider Data Type Definition](images/Slider-Data-Type-Definition.png) + +## Content Example + +
+ +
+ +## MVC View Example + +### Without Models Builder + +```csharp +@if (Model.HasValue("singleValueSlider")) +{ + var value = Model.Value("singleValueSlider"); +

@value

+} + +@if (Model.HasValue("multiValueSlider")) +{ + var value = Model.Value>("multiValueSlider"); +

@(value.Minimum) and @(value.Maximum)

+} +``` + +### With Models Builder + +```csharp +// with a range off +@if (Model.SingleValueSlider != null) +{ + var value = Model.SingleValueSlider; +

@value

+} + +// with a range on +@if (Model.MultiValueSlider != null) +{ + var minValue = Model.MultiValueSlider.Minimum; + var maxValue = Model.MultiValueSlider.Maximum; +

@minValue and @maxValue

+} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +### With a range off + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'singleValueSlider'. + content.SetValue("singleValueSlider", 10); + + // Save the change + ContentService.Save(content); +} +``` + +### With a range on + +```csharp +@using Umbraco.Cms.Core.Models +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Create a variable for the desired value of the 'multiValueSlider' property + var range = new Range {Minimum = 10, Maximum = 12}; + + // Set the value of the property with alias 'multiValueSlider'. + content.SetValue("multiValueSlider", range); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'singleValueSlider' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.SingleValueSlider).Alias, 10); + + // Set the value of the property with alias 'multiValueSlider' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MultiValueSlider).Alias, new Range {Minimum = 10, Maximum = 12}); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/tags.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/tags.md new file mode 100644 index 00000000000..117c0ed9042 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/tags.md @@ -0,0 +1,120 @@ +# Tags + +`Schema Alias: Umbraco.Tags` + +`UI Alias: Umb.PropertyEditorUi.Tags` + +`Returns: IEnumerable` + +The Tags property editor allows you to add multiple tags to a node. + +## Data Type Definition Example + +![Tags Data Type Definition Example](images/tags-DataType.png) + +### Tag group + +The **Tag group** setting provides a way to categorize your tags in groups. So for each category you will create a new instance of the Tags property editor and setup the unique category name for each instance. Whenever a tag is added to an instance of the tags property editor it's added to the tag group, which means it will appear in the Typeahead list when you start to add another tag. Only tags that belong to the specified group will be listed. If you have a "Frontend" group and a "Backend" group the tags from the "Frontend" group will only be listed if you're adding a tag to the Tags property editor configured with the "Frontend" group name and vice versa. + +### Storage type + +Data can be saved in either Comma-Separated Values (CSV) format or in JSON format. By default data is saved in JSON format. The difference between using CSV and JSON is that with JSON you can save a tag, which includes comma separated values. + +There are built-in property value converters, which means you don't need to worry about writing them yourself or parse the JSON output when choosing "JSON" in the storage type field. Therefore [the last code example](tags.md#mvc-view-example---displays-a-list-of-tags) on this page will work out of the box without further ado. + +## Content Examples + +### CSV tags + +![CSV tags example](../built-in-property-editors/images/Csv-example-v8.png) + +### JSON tags + +![JSON tags example](../built-in-property-editors/images/Json-example-v8.png) + +### Tags typeahead + +Whenever a tag has been added it will be visible in the typeahead when you start typing on other pages. + +![Tags typeahead example](../built-in-property-editors/images/Typeahead-v8.png) + +## MVC View Example - displays a list of tags + +### Multiple items - with Models Builder + +```csharp +@if(Model.Tags.Any()){ +
    + @foreach(var tag in Model.Tags){ +
  • @tag
  • + } +
+} +``` + +### Multiple items - without Models Builder + +```csharp +@if(Model.HasValue("tags")) +{ + var tags = Model.Value>("tags"); +
    + @foreach(var tag in tags) + { +
  • @tag
  • + } +
+} +``` + +### Setting Tags Programmatically + +You can use the ContentService to create and update Umbraco content from c# code, when setting tags there is an extension method (SetTagsValue) on IContentBase that helps you set the value for a Tags property. Remember to add the using statement for `Umbraco.Core.Models` to take advantage of it. + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Serialization +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@inject IJsonSerializer Serializer +@{ + // Create a variable for the GUID of the page you want to update + var guid = Guid.Parse("9daf8585-6ab6-4ac2-98f0-28bf83aeea6e"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'tags'. + content.SetValue("tags", Serializer.Serialize(new[] { "News", "Umbraco", "Example", "Setting Tags", "Helper" })); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled, you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'tags' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Tags).Alias, Serializer.Serialize(new[] { "News", "Umbraco", "Example", "Setting Tags" })); +} +``` + +### More on working with Tags + +More on working with Tags (query all of them) can be found at the [UmbracoHelper reference page](../../../../reference/querying/umbracohelper.md#working-with-tags) diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textarea.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textarea.md new file mode 100644 index 00000000000..646f6f544e6 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textarea.md @@ -0,0 +1,93 @@ +# Textarea + +`Schema Alias: Umbraco.TextArea` + +`UI Alias: Umb.PropertyEditorUi.TextArea` + +`Returns: String` + +Textarea is an HTML textarea control for multiple lines of text. It can be configured to have a fixed character limit, as well as define how big the space for writing can be. By default, there is no character limit unless it's specifically set to a specific value like 200 for instance. If you don't specify the number of rows, 10 will be the amount of rows the textarea will be occupying, unless changed to a custom value. + +## Data Type Definition Example + +![Textarea Data Type Definition](images/Textarea-Setup.png) + +## Settings + +## Content Example + +### Without a character and rows limit + +![Textarea Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-v8.png) + +### With a character limit and rows limit + +![Textbox Content Example With Limits](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textarea-Content-Limit-v8.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (Model.HasValue("description")){ +

@(Model.Value("description"))

+ } +} +``` + +### With Models Builder + +```csharp +@if (!Model.HasValue(Model.Description)) +{ +

@Model.Description

+} +``` + +## Add value programmatically + +See the example below to learn how a value can be added or changed programmatically to a Textarea property. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of your page + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've just defined + var content = ContentService.GetById(guid); + + // Set the value of the property with alias 'description' + content.SetValue("description", "This is some text for the text area!"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + + // Set the value of the property with alias 'description' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.Description).Alias, "This is some text for the text area!"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textbox.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textbox.md new file mode 100644 index 00000000000..56e56e92d11 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/textbox.md @@ -0,0 +1,100 @@ +--- +description: How to use the TextBox property editors in Umbraco CMS. +--- + +# Textbox + +`Schema Alias: Umbraco.TextBox` + +`UI Alias: Umb.PropertyEditorUi.TextBox` + +`Returns: String` + +Textbox is an HTML input control for text. It can be configured to have a fixed character limit. The default maximum amount of characters is 512 unless it's specifically changed to a lower amount. + +## Data Type Definition Example + +![Textbox Data Type Definition](images/Textbox-Setup.png) + +## Content Example + +### Without a character limit + +![Textbox Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-v8.png) + +### With a character limit + +![Textbox Content Example Without a Character Limit](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Textbox-Content-Limit-v8.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + // Perform an null-check on the field with alias 'pageTitle' + if (Model.HasValue("pageTitle")){ + // Print the value of the field with alias 'pageTitle' +

@(Model.Value("pageTitle"))

+ } +} +``` + +### With Models Builder + +```csharp +@{ + // Perform an null-check on the field with alias 'pageTitle' + @if (!Model.HasValue(Model.PageTitle)) + { + // Print the value of the field with alias 'pageTitle' +

@Model.PageTitle

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("32e60db4-1283-4caa-9645-f2153f9888ef"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'pageTitle' + content.SetValue("pageTitle", "Umbraco Demo"); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'pageTitle' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.PageTitle).Alias, "Umbraco Demo"); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/true-false.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/true-false.md new file mode 100644 index 00000000000..db185c002a8 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/true-false.md @@ -0,0 +1,91 @@ +# Toggle + +`Schema Alias: Umbraco.TrueFalse` + +`UI Alias: Umb.PropertyEditorUi.Toggle` + +`Returns: Boolean` + +Toggle is a standard checkbox which saves either 0 or 1, depending on the checkbox being checked or not. + +## Data Type Definition Example + +![True/False Data Type Definition](images/Checkbox-Data-Type.png) + +The Toggle property has a setting which allows you to set the default value of the checkbox, either checked (true) or unchecked (false). + +It is also possible to define a label, that will be displayed next to the checkbox on the content. + +## Content Example + +![No Edit Content Example](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/Checkbox-Content.png) + +## MVC View Example + +### Without Models Builder + +```csharp +@{ + if (!Model.Value("myCheckBox")) + { +

The Checkbox is not checked!

+ } +} +``` + +### With Models Builder + +```csharp +@{ + if (!Model.MyCheckbox) + { +

The Checkbox is not checked!

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'myCheckBox' + content.SetValue("myCheckBox", true); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'myCheckBox' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.MyCheckBox).Alias, true); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/user-picker.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/user-picker.md new file mode 100644 index 00000000000..4a43c573393 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/user-picker.md @@ -0,0 +1,105 @@ +# User Picker + +`Schema Alias: Umbraco.UserPicker` + +`UI Alias: Umb.PropertyEditorUi.UserPicker` + +`Returns: IPublishedContent` + +The user picker opens a panel to pick a specific user from the Users section. The value saved is of type IPublishedContent. + +## Data Type Definition Example + +![Media Picker Data Type Definition](images/User-Picker-DataType.png) + +## Content Example + +![Member Picker Content](../../../../../../10/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/images/User-Picker-Content-v8.png) + +## MVC View Example + +{% hint style="info" %} +Getting the Value of the property will return the user ID - properties of the User can be accessed by referencing UserService. +{% endhint %} + +### Without Models Builder + +```csharp +@using Umbraco.Cms.Core.Services; +@inject IUserService UserService; +@{ + + if (Model.Value("userPicker") != null) + { + var us = UserService; + var username = us.GetUserById(Model.Value("userPicker")).Name; + +

This is the chosen person: @username

+

This returns the id value of chosen person: @Model.Value("userPicker")

+ } +} +``` + +### With Models Builder + +```csharp +@using Umbraco.Cms.Core.Services; +@inject IUserService UserService; +@{ + if (Model.UserPicker != null) + { + + var us = UserService; + var user = us.GetUserById((int)Model.UserPicker); + +

This is the chosen person: @user.Name

+

This returns the id value of chosen person: @user.Id)

+ } +} +``` + +## Add values programmatically + +See the example below to see how a value can be added or changed programmatically. To update a value of a property editor you need the [Content Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html). + +{% hint style="info" %} +The example below demonstrates how to add values programmatically using a Razor view. However, this is used for illustrative purposes only and is not the recommended method for production environments. +{% endhint %} + +```csharp +@using Umbraco.Cms.Core.Services +@inject IContentService ContentService +@{ + // Create a variable for the GUID of the page you want to update + var guid = new Guid("796a8d5c-b7bb-46d9-bc57-ab834d0d1248"); + + // Get the page using the GUID you've defined + var content = ContentService.GetById(guid); // ID of your page + + // Set the value of the property with alias 'userPicker'. The value is the specific ID of the user + content.SetValue("userPicker", -1); + + // Save the change + ContentService.Save(content); +} +``` + +Although the use of a GUID is preferable, you can also use the numeric ID to get the page: + +```csharp +@{ + // Get the page using it's id + var content = ContentService.GetById(1234); +} +``` + +If Models Builder is enabled you can get the alias of the desired property without using a magic string: + +```csharp +@using Umbraco.Cms.Core.PublishedCache +@inject IPublishedContentTypeCache PublishedContentTypeCache +@{ + // Set the value of the property with alias 'userPicker' + content.SetValue(Home.GetModelPropertyType(PublishedContentTypeCache, x => x.UserPicker).Alias, -1); +} +``` diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/Media-picker-dataType-v9.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/Media-picker-dataType-v9.png new file mode 100644 index 00000000000..36cdbba266d Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/Media-picker-dataType-v9.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-column-content-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-column-content-picker.png new file mode 100644 index 00000000000..f0e664a416b Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-column-content-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-property-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-property-picker.png new file mode 100644 index 00000000000..375af70dc02 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-property-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-view-cards-content-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-view-cards-content-picker.png new file mode 100644 index 00000000000..cfb2e51eb9f Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/collection-view-cards-content-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-picked-value.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-picked-value.png new file mode 100644 index 00000000000..9726d5c05ea Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-picked-value.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-property.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-property.png new file mode 100644 index 00000000000..a20251e8876 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/content-picker-property.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/images/media-picker.png b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/media-picker.png new file mode 100644 index 00000000000..0c52763cd41 Binary files /dev/null and b/17/umbraco-cms/fundamentals/backoffice/property-editors/images/media-picker.png differ diff --git a/17/umbraco-cms/fundamentals/backoffice/sections.md b/17/umbraco-cms/fundamentals/backoffice/sections.md new file mode 100644 index 00000000000..53fac242ebc --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/sections.md @@ -0,0 +1,131 @@ +--- +description: >- + In this article you can learn more about the various sections you can find + within the Umbraco Backoffice. +--- + +# Sections + +A section in Umbraco is where you perform specific tasks related to a particular area of Umbraco. For example, Content, Settings, and Users are all sections. You can navigate between the different sections by clicking the corresponding icon in the section menu positioned at the top of the Backoffice. + +![The Section menu is the horizontal menu located at the top of the Umbraco Backoffice.](images/highlight-sections-v14.png) + +Below is a short overview of the default sections in Umbraco CMS: + +## Content + +The Content section contains the content nodes that make up the website. Content is displayed as nodes in the Content tree. + +Nodes in Umbraco can display the following content states: + +* Grayed-out nodes are not published yet. +* Nodes that are currently locked using the Public Access feature. +* Content nodes that contain a collection of nodes. + +To create content, you must define it using Document Types. + +For more information, see the [Defining Content](../data/defining-content/) article. + +## Media + +The Media section contains the media for the website. You can create folders and upload media files, such as images and PDFs. Additionally, you can customize the existing Media Types or define your own from the Settings section. + +For more information, see the [Creating Media](../data/creating-media/) article. + +## Settings + +The Settings section allows you to manage website layout files, languages, media, and content types. It also gives you access to more advanced features such as the Log Viewer and extension insights. + +The Settings section consists of: + +**Structure** + +* Document Types +* Media Types +* Member Types +* Data Types +* Languages +* Document Blueprints + +**Templating** + +* Templates (`.cshtml` files) +* Partial views (`.cshtml` files) +* Stylesheets (`.css` files) +* Scripts (`.js` files) + +**Advanced** + +* Relations +* Log Viewer +* Extension Insights +* Webhooks + +The **Settings** section in the Umbraco backoffice has its own set of default dashboards. + +For more information, see the [Settings Dashboards](settings-dashboards.md) article. + +## Packages + +In this section, you can browse the different packages available for your Umbraco solution. You can also get an overview of all the packages you have installed or created. + +For more information, see the [Packages](../../extending/packages/) article. + +## Users + +The Users section allows administrators to manage user accounts, assign permissions, set user roles, and monitor user activity within the backoffice. It provides control over who can access and modify content, media, and settings in the CMS. + +For more information, see the [Users](../data/users/README.md) article. + +## Members + +The Members section allows to create and manage member profiles, set up member groups, and control Member's access to restricted content on the website. + +For more information, see the [Members](../data/members.md) article. + +## Dictionary + +The Dictionary section is where you create and manage Dictionary Items. By managing these dictionary items, you can ensure consistent and efficient content translation and maintenance across different languages. + +For more information, see the [Dictionary Items](../data/dictionary-items.md) article. + +## Add-Ons + +To enhance Umbraco's functionality, you can integrate plugins and extensions tailored to specific needs. These add-ons expand Umbraco's capabilities, allowing for a more customized and powerful content management experience. + +For example, you can start with core Umbraco features and later decide to integrate additional products. Currently, Umbraco supports add-on products like: + +* **Forms:** Simplifies the creation and management of Forms. +* **Deploy:** Facilitates smooth deployment processes. +* **Workflow:** Enhances content workflows and approval processes. +* **Commerce:** Adds e-commerce capabilities to your site. +* **UI Builder:** Helps in designing and customizing the user interface. + +When you add an add-on product to Umbraco, it appears in the Backoffice as a new section, seamlessly extending your content management capabilities. + +![Add-Ons Section](images/Add-ons.png) + +If you wish to explore the unique features and use cases of Umbraco products, see the [Exploring the Umbraco Products](https://docs.umbraco.com/welcome/getting-started/exploring-the-umbraco-products) article. + +For more information about extending the Umbraco platform through packages and integrations, see the [Umbraco DXP](https://docs.umbraco.com/umbraco-dxp) documentation. + +## Help Section + +The Help section in Umbraco provides documentation and resources to assist in understanding and effectively using the Umbraco CMS. It typically includes the following in the _Getting Started_ Dashboard: + +* **Documentation**: Comprehensive guides, tutorials, and references covering different aspects of Umbraco. +* **Community Forums**: Access to forums where you can ask questions, share knowledge, and seek assistance from other Umbraco community members. +* **Resources**: Stay updated with the latest news, access documentation, watch free video tutorials, and register for live demos. +* **Training**: Learn how to effectively use Umbraco through structured courses, webinars, and hands-on tutorials designed to enhance your proficiency with the CMS. + +The Help section serves as a valuable resource hub in navigating and leveraging the capabilities of the Umbraco CMS effectively. + +## Custom Sections + +Along with the default sections that come with Umbraco, you can create your own [Custom Sections](../../customizing/extending-overview/extension-types/sections/section.md). + +## Access based on User Group + +A User can access a particular section based on the User Group permissions. + +Learn more about how to configure the permissions in the article about [backoffice users](../data/users/README.md). diff --git a/17/umbraco-cms/fundamentals/backoffice/settings-dashboards.md b/17/umbraco-cms/fundamentals/backoffice/settings-dashboards.md new file mode 100644 index 00000000000..edfc19505c0 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/settings-dashboards.md @@ -0,0 +1,112 @@ +--- +description: >- + A guide displaying the options available in the Settings section in Umbraco + CMS backoffice. +--- + +# Settings Dashboards + +The **Settings** section of the Umbraco backoffice has its own set of default dashboards. In this article, you can get an overview of each dashboard available in the **Settings** section: + +
+ +Welcome + +The Welcome dashboard is the first dashboard in the Settings section. Like all dashboards, it has a customizable view and links to different resources for developing your Umbraco website. + +For more information about creating custom dashboards, see the [Dashboards](../../customizing/extending-overview/extension-types/dashboard.md) article. + +
+ +
+ +Examine Management + +The Examine Management dashboard provides an overview of the Examine functionality available directly within the Umbraco backoffice. The Umbraco backoffice allows you to view details about your Examine indexes and searchers - all in one place. You can see which fields are being indexed and rebuild the indexes if there's a problem. You can also test keywords to see what results will be returned. + +For more information about Examine Management, see the [Examine Management](../../reference/searching/examine/examine-management.md) article. + +
+ +
+ +Published Status + +The Published Status dashboard displays the status of your site in the Published Cache Status section alongside the Content and Media nodes value. The Caches section provides three options: Memory Cache, Database Cache, and Internals. + +* Memory Cache - Reloads the in-memory cache by entirely reloading it from the database cache. Use it when you think that the memory cache has not been properly refreshed. +* Database Cache - Rebuilds the database cache that is the content of the `cmsContentNu` table. Use it when reloading the Memory Cache is not enough and you think that the database cache has not been properly generated. +* Internals - Lets you trigger a NuCache snapshots collection. + +{% hint style="info"%} +As of Umbraco 15 `IPublishedSnapshot`, `IPublishedSnapshotAccessor`, and `SnapshotCache` are all obsolete. +{%endhint%} + +
+ +
+ +Models Builder + +Models builder is a tool that can generate a complete set of strongly-typed published content models for Umbraco. Models are available in both controllers and views. When using the Models Builder, the content cache does not return `IPublishedContent` objects anymore but returns strongly typed models implementing `IPublishedContent`. + +The Models Builder dashboard displays the following information: + +* Details on how Models Builder is configured, that is: `InMemoryAuto`, `Nothing`, `SourceCodeAuto`, and `SourceCodeManual`. +* Provides a button to generate models (if the models mode is `SourceCodeManual` mode only). +* Reports the last error (if any) that would have prevented models from being properly generated. + +For more information about Models Builder, see the [Models Builder](../../reference/templating/modelsbuilder/) article. + +
+ +
+ +Health Check + +Health Checks are used to determine the status of your Umbraco project. It is a handy list of checks to see if your Umbraco installation is configured according to best practices. It's possible to add your custom-built health checks. + +For more information about Health Checks, see the [Health Check](../../extending/health-check/) articles. + +
+ +
+ +Profiling + +You can use the built-in performance profiler to assess the performance when rendering pages. To activate the profiler for a specific page rendering, add `umbDebug=true` to the querystring when requesting the page. + +The Profiling dashboard provides a toggle option - `Activate the profiler by default` to keep the profiler active by default for all page renderings. You can use this option without having to set `umbDebug=true` on each page request. The toggle button sets a cookie named `UMB-DEBUG` in your browser, which then activates the profiler automatically. + +For more information about MiniProfiler, see the [MiniProfiler](../code/debugging/#miniprofiler) section in the [Debugging](../code/debugging/) article. + +
+ +
+ +Telemetry Data + +The Telemetry Data dashboard is a consent screen that is used for collecting system and usage information from your installation. Here, you can see what type of data is being collected and even adjust the level of reporting. Currently, there are three levels available: **Minimal**, **Basic**, and **Detailed**. + +**Detailed** is the default option where the data sent contains: + +* Anonymized site ID, Umbraco version, and packages installed. +* Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use. +* System information: Webserver, server OS, server framework, server OS language, and database provider. +* Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode. + +**Basic** contains: + +* Anonymized site ID, Umbraco version, and packages installed. + +**Minimal** contains: + +* Anonymized site ID only + +You can see the specific data being sent on each of the levels directly in the **Telemetry Data** Dashboard. + +Additionally, Telemetry Data also sends anonymized, analytical data on package usage in Umbraco. Having solid data on package usage is important for both package developers and the Umbraco ecosystem. + +For more information about Package Telemetry, see the [Package Telemetry](https://umbraco.com/blog/umbraco-92-release/) section in the Umbraco 9.2 Release Blog Post. + +
diff --git a/17/umbraco-cms/fundamentals/backoffice/sidebar.md b/17/umbraco-cms/fundamentals/backoffice/sidebar.md new file mode 100644 index 00000000000..9afdd23c903 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/sidebar.md @@ -0,0 +1,23 @@ +--- +description: >- + This section explains how the concept of infinite editing using the Sidebar in the Umbraco + backoffice works. +--- + +# Sidebar + +{% hint style="info" %} +Sidebar was previously called Infinite editor. +{% endhint %} + +This feature enables you to work with your content without losing the context of what you are doing. + +Document Types are in different sections than content but the sidebar enables you to make changes to them directly from the content you are editing. + +![Sidebar](images/update-dropdown-options.gif) + +In the example showcased above, new options are being added to a Data Type, without losing the context of the content. The example also shows how you can edit images, without being sent to the 'Media' section. + +## Customize + +The sidebar is a feature that comes out of the box with Umbraco. The feature can be customized, which enables you as a developer to improve the workflow for your editors. diff --git a/17/umbraco-cms/fundamentals/backoffice/variants.md b/17/umbraco-cms/fundamentals/backoffice/variants.md new file mode 100644 index 00000000000..df4854af045 --- /dev/null +++ b/17/umbraco-cms/fundamentals/backoffice/variants.md @@ -0,0 +1,95 @@ +--- +description: >- + Learn how to use language variants to output your content in multiple + languages. +--- + +# Language Variants + +Language Variants allows you to vary content by culture, so you can allow a content node to exist in multiple languages. + +This article will cover the different aspects of enabling and working with language variants on your Umbraco website. + +## Contents + +* [Video tutorial](variants.md#video-tutorial) +* [How to enable Language Variants](variants.md#how-to-enable-language-variants) +* [Enabling Language Variants on Document Types](variants.md#enabling-language-variants-on-document-types) +* [Working with Language Variants on content](variants.md#working-with-language-variants-on-content) +* [Test your language variants](variants.md#test-your-language-variants) +* [Control User Group permissions on language variants](variants.md#control-user-group-permissions-on-language-variants) +* [Related Links](variants.md#related-links) + +## Video tutorial + +{% embed url="https://www.youtube.com/watch?ab_channel=UmbracoLearningBase&v=TWLqt-jVdyQ" %} +How to use Language Variants in Umbraco +{% endembed %} + +## How to enable Language Variants + +To work with Language Variants you need to have more than one language enabled. This can be done from the `Settings` section: + +![Adding a language](images/adding-a-language.png) + +{% hint style="info" %} +You will always have one default language but each language can be set to mandatory. +{% endhint %} + +## Enabling Language Variants on Document Types + +Now that there are two languages to vary the content with, it needs to be enabled on the Document Types. To do so: + +1. Go to the Document Type in the **structure** section. +2. Open the **settings** page. +3. Toggle **Allow vary by culture**. + +
+ +To allow a property on the Document Type to be varied it will have to be enabled for the property: + +![Allowing Variance on properties](images/varying-properties.png) + +## Working with Language Variants on content + +When you return to your content node you will notice two things: + +1. At the top of the Content tree there will now be a dropdown so you can show the Content tree in the language of your choice. +2. To the right of the content name there is now a dropdown where you can select a language. You can also open a split view so you can see two languages at once. + + ![Allowing Variance on properties](images/Allowing-Variance-on-properties.png) + +To read about how you render variant content in Templates, check out the [rendering content section](../design/rendering-content.md). + +## Test your language variants + +Culture and hostnames must be added to your language sites before the content can be tested for variants: + +1. Click **...** next to the Home node and select **Culture and Hostnames**. +2. Add a specific URL per language and save. For eg: An English language variant with English (United States) as the language can be given a specific URL `https://yourwebsite.com/en-us` and a Danish language variant can be given a specific URL `https://yourwebsite.com/dk`. + +The Info content app should now show specific URLs for your language variants. + +## Control User Group permissions on language variants + +{% hint style="info" %} +This feature is available from Umbraco version 10.2. +{% endhint %} + +When you are working with a multilingual site you might want to control who can edit the different variations of the content on the website. + +This can be controlled on a User Group level. All default User Groups, except the Sensitive data group, have access to all languages out of the box. + +When "Allow access to all languages" is not checked, languages can be added and/or removed. This is to determine which variants the users in the user group have access to. + +![Assign access to all or individual languages on the User Group](images/Assign-Access-Languages.png) + +{% hint style="info" %} +Even though the language permissions have been set, a user will still be able to view and browse all the language variations. The permission setting will ensure that only the added languages are editable by users of the User Group. +{% endhint %} + +## Related Links + +* [Umbraco 8: Language Variants (official blog post from Umbraco HQ)](https://umbraco.com/blog/umbraco-8-language-variants/) +* [Language variations](../../reference/language-variation.md) +* [Render varied content in Templates](../design/rendering-content.md) diff --git a/17/umbraco-cms/fundamentals/code/README.md b/17/umbraco-cms/fundamentals/code/README.md new file mode 100644 index 00000000000..f39d3031a5f --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/README.md @@ -0,0 +1,21 @@ +# Code + +## [Using Umbraco's Service APIs](umbraco-services.md) + +Create and update entities in Umbraco from code. + +## [Subscribing to Notifications](subscribing-to-notifications.md) + +Subscribe to notifications to execute custom code on a number of operations. + +## [Creating Forms](creating-forms.md) + +Create, submit and handle HTML forms with controllers. + +## [Debugging your Umbraco site](debugging/README.md) + +Using Tracing and MiniProfiler to debug your code. + +## [Source/Version Control](source-control.md) + +General advice on source controlling your Umbraco implementation. diff --git a/17/umbraco-cms/fundamentals/code/creating-forms.md b/17/umbraco-cms/fundamentals/code/creating-forms.md new file mode 100644 index 00000000000..ea445636460 --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/creating-forms.md @@ -0,0 +1,126 @@ +--- +description: "Information on creating forms in Umbraco" +--- + + +# Creating Forms + +Creating forms requires that you know your way around .NET Core MVC. So if you are familiar with adding view models, views and controllers you are ready to make your first form. + +{% hint style="info" %} +You can also use [Umbraco forms](https://umbraco.com/products/add-ons/forms/). It lets you and/or your editors create and handle forms in the backoffice. This includes setting up validation, redirecting and storing and sending form data. Great UI, extendable and supported by Umbraco HQ. +{% endhint %} + +In this example we'll create a basic contact form containing a name, email and message field. + +## Creating the view model + +First, we're going to create the model for the contact form by adding a new class to the `/Models` folder. If the folder doesn't already exist, create it at the root of your website. Let's call it `ContactFormViewModel.cs` + +```csharp +namespace MyFirstForm.Models; + +public class ContactFormViewModel +{ + public string Name { get; set; } + public string Email { get; set; } + public string Message { get; set; } +} +``` + +Build your solution after adding the model. + +### Creating the view + +Next, we add the view for the form to the `/View/Partials` folder. Because we've added the model and built the solution we can add it as a strongly typed view. + +Name your view "ContactForm". + +The view can be built with standard MVC helpers: + +```csharp +@using MyFirstForm.Controllers +@model MyFirstForm.Models.ContactFormViewModel + +@using (Html.BeginUmbracoForm(nameof(ContactFormController.Submit))) +{ +
+ + +
+
+ + +
+
+ + +
+
+ +} +``` + +### Adding the controller + +Finally, we're going to add the controller. Create a new empty class in the `/Controllers` folder (if the folder doesn't already exist, create it at the root of the website). Name it `ContactFormController` and make it inherit from `SurfaceController`. Inheriting from `SurfaceController` requires that you call its base constructor. If you are using an IDE: Integrated Development Environment, this can be done automatically. + +```csharp +using Microsoft.AspNetCore.Mvc; +using MyFirstForm.Models; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Cms.Web.Website.Controllers; + +namespace MyFirstForm.Controllers; + +public class ContactFormController : SurfaceController +{ + public ContactFormController( + IUmbracoContextAccessor umbracoContextAccessor, + IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger profilingLogger, + IPublishedUrlProvider publishedUrlProvider) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + {} + + [HttpPost] + public IActionResult Submit(ContactFormViewModel model) + { + if (!ModelState.IsValid) + { + return CurrentUmbracoPage(); + } + + // Work with form data here + + return RedirectToCurrentUmbracoPage(); + } +} +``` + +If the model state is invalid, `CurrentUmbracoPage()` will send the user back to the form. If valid, you can work with the form data, for example, sending an email to site admin and then `RedirectToCurrentUmbracoPage();`. + +## Adding the form to a template + +You can add the form to a template by rendering the partial view: + +```csharp +@using MyFirstForm.Models; + +@{ + Html.RenderPartial("~/Views/Partials/ContactForm.cshtml", new ContactFormViewModel()); +} +``` + +### More information + +- [Surface Controllers](../../reference/routing/surface-controllers/README.md) +- [Custom controllers](../../reference/routing/custom-controllers.md) +- [Routing](../../reference/routing/README.md) diff --git a/17/umbraco-cms/fundamentals/code/debugging/README.md b/17/umbraco-cms/fundamentals/code/debugging/README.md new file mode 100644 index 00000000000..317cc2df3dd --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/debugging/README.md @@ -0,0 +1,128 @@ +# Debugging + +During the development of your Umbraco site you can debug and profile the code you have written to analyse and discover bottlenecks in your code. + +To perform proper debugging on your site you need to set your application to have debug enabled. This can be done by setting `Umbraco:CMS:Hosting:Debug="true"` for example in the `appsettings.json` file: + +```json +{ + "Umbraco": { + "CMS": { + "Hosting": { + "Debug": true + } + } + } +} +``` + +{% hint style="warning" %} +Debug should always be set to false in production. +{% endhint %} + +## Tracing + +Tracing and trace logging are two names for the same technique. You need to configure which log messages you want to log. + +### Enabling Trace Logging + +{% hint style="warning" %} +Do not enable trace logging in your production environment! It reveals an awful lot of (sensitive) information about your production environment. +{% endhint %} + +We recommend at least logging the following namespace at minimum (Verbose) level to enable valuable trace logging. Thereby you will have information about all endpoints that have been executed. + +```json +{ + "Serilog": { + "MinimumLevel": { + "Override": { + "Microsoft.AspNetCore.Mvc": "Verbose" + } + } + } +} +``` + +The logged messages can as always be monitored in the log viewer in backoffice + +## MiniProfiler + +Umbraco includes the Mini Profiler project in its core (see [https://miniprofiler.com](https://miniprofiler.com) for more details). The MiniProfiler profiles your code method calls, giving you a greater insight into code duration and query time for (for example) underlying SQL queries. It's great for tracking down performance issues in your site's implementation. + +### Displaying the MiniProfiler + +To display the profiler ensure that the configuration `Umbraco:CMS:Hosting:Debug` is set to `true` in the appSettings.json file. Thereafter you can add `?umbDebug=true` to the query string of any request. + +Also, ensure your template calls `@Html.RenderProfiler()` as one of the last things. + +
+ +If you click 'Show Trivial' you can seen the kind of detail the MiniProfiler makes available to you about the execution path of your page: + +
+ +and any underlying SQL Statements that are being executed for a part of the execution: + +
+ +![Underlying SQL query details](../../../../../10/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-details.png) + +### Writing to the MiniProfiler + +If you feel like a part of your application is slow you can use the MiniProfiler in your code to test the speed of it. + +All you have to do is inject the IProfiler interface and add a step around your logic: + +```csharp +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.Common.Controllers; + +namespace MyCustomUmbracoProject; + +public class RootController : RenderController +{ + private readonly IProfiler _profiler; + + public RootController( + IProfiler profiler, + ILogger logger, + ICompositeViewEngine compositeViewEngine, + IUmbracoContextAccessor umbracoContextAccessor) + : base(logger, compositeViewEngine, umbracoContextAccessor) + { + _profiler = profiler; + } + + public override IActionResult Index() + { + // Perform a step + using (_profiler.Step("Sleep")) + { + System.Threading.Thread.Sleep(1000); + } + + return base.Index(); + } +} +``` + +and now in the profiler you can see: + +![Show Trivial](../../../../../10/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-write.png) + +## Umbraco Productivity Tool - Chrome Extension + +If you are using the Google Chrome browser you can install this [Umbraco Productivity Tool Chrome Extension](https://chrome.google.com/webstore/detail/umbraco-productivity/kepkgaeokeknlghbiiipbhgclikjgkdp?hl=en). + +This will allow you to quickly switch between debugging with the MiniProfiler, Trace viewer and normal mode. + +![Umbraco Productivity Tool](../../../../../10/umbraco-cms/fundamentals/code/debugging/images/chrome-tool.png) + +## [Logging](logging.md) + +Learn how Umbraco writes log files and how you can write to them. diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/application-trace.png b/17/umbraco-cms/fundamentals/code/debugging/images/application-trace.png new file mode 100644 index 00000000000..45ab8c78f27 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/application-trace.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/chrome-tool.png b/17/umbraco-cms/fundamentals/code/debugging/images/chrome-tool.png new file mode 100644 index 00000000000..922074898af Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/chrome-tool.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/miniprofile-warning.png b/17/umbraco-cms/fundamentals/code/debugging/images/miniprofile-warning.png new file mode 100644 index 00000000000..db8db49a1d2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/miniprofile-warning.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/show-trivial.png b/17/umbraco-cms/fundamentals/code/debugging/images/show-trivial.png new file mode 100644 index 00000000000..44926efa9b1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/show-trivial.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/trace-logs.png b/17/umbraco-cms/fundamentals/code/debugging/images/trace-logs.png new file mode 100644 index 00000000000..d6795286e4f Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/trace-logs.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/trace-request-details.png b/17/umbraco-cms/fundamentals/code/debugging/images/trace-request-details.png new file mode 100644 index 00000000000..f698d1f2994 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/trace-request-details.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/umb-debug-equals-true.png b/17/umbraco-cms/fundamentals/code/debugging/images/umb-debug-equals-true.png new file mode 100644 index 00000000000..abd3463ac8b Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/umb-debug-equals-true.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/umbraco-productivity-chrome-extension.png b/17/umbraco-cms/fundamentals/code/debugging/images/umbraco-productivity-chrome-extension.png new file mode 100644 index 00000000000..6eba3609a87 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/umbraco-productivity-chrome-extension.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/underlying-sql-queries.png b/17/umbraco-cms/fundamentals/code/debugging/images/underlying-sql-queries.png new file mode 100644 index 00000000000..2ca19c19b50 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/underlying-sql-queries.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-details.png b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-details.png new file mode 100644 index 00000000000..9535949c1e3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-details.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-trigger.png b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-trigger.png new file mode 100644 index 00000000000..ea1a4c208c1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-sql-trigger.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-trivial.png b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-trivial.png new file mode 100644 index 00000000000..7b36e615056 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-trivial.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-view.png b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-view.png new file mode 100644 index 00000000000..db39a3caab1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-view.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-write.png b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-write.png new file mode 100644 index 00000000000..cd40b9f107c Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-miniprofiler-write.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace-details.PNG b/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace-details.PNG new file mode 100644 index 00000000000..245d2be7418 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace-details.PNG differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace.PNG b/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace.PNG new file mode 100644 index 00000000000..5b8f095497b Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/v8-trace.PNG differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/images/writing-to-miniprofiler.png b/17/umbraco-cms/fundamentals/code/debugging/images/writing-to-miniprofiler.png new file mode 100644 index 00000000000..7f9cbcfa123 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/debugging/images/writing-to-miniprofiler.png differ diff --git a/17/umbraco-cms/fundamentals/code/debugging/logging.md b/17/umbraco-cms/fundamentals/code/debugging/logging.md new file mode 100644 index 00000000000..7d7a1b278ae --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/debugging/logging.md @@ -0,0 +1,157 @@ +# Logging + +In Umbraco we use the underlying logging framework of [Serilog](https://serilog.net/). + +Out of the box, we write a JSON log file that contains a more detailed logfile. This allows tools to perform searches and correlations on log patterns more efficiently. + +The default location of this file is written to `umbraco/Logs` and contains the Machine name, along with the date too: + +* `umbraco/Logs/UmbracoTraceLog.DELLBOOK.20210809.json` + +## Video overview + +{% embed url="" %} +Watch this video to get an overview of how to view and manage logs and logfiles for your Umbraco CMS website. +{% endembed %} + +## Structured logging + +Serilog is a logging framework that allows us to do structured logging or write log messages using the message template format. This allows us to have a more detailed log message, rather than the traditional text message in a long txt file. + +```cs +2021-08-10 09:33:23,677 [P25776/D1/T22] INFO Umbraco.Cms.Core.Services.Implement.ContentService - Document Home (id=1062) has been published. +``` + +Here is an example of the same log message represented as JSON. More information is available and allows you to search and filter logs based on these properties with an appropriate logging system. + +```json +{ + "@t":"2021-08-10T08:33:23.6778640Z", + "@mt":"Document {ContentName} (id={ContentId}) has been published.", + "ContentName":"Home", + "ContentId":1062, + "SourceContext":"Umbraco.Cms.Core.Services.Implement.ContentService", + "ActionId":"7726d745-d502-4b2d-b55e-97731308041b", + "ActionName":"Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PostSave (Umbraco.Web.BackOffice)", + "RequestId":"8000000c-0012-fb00-b63f-84710c7967bb", + "RequestPath":"/umbraco/backoffice/umbracoapi/content/PostSave", + "ProcessId":25776, + "ProcessName":"iisexpress", + "ThreadId":22, + "AppDomainId":1, + "AppDomainAppId":"2f4961977e5c252fa708f7d83915c269b53a620c", + "MachineName":"DELLBOOK", + "Log4NetLevel":"INFO ", + "HttpRequestId":"318b6dd4-b127-4da3-8339-37701f4d1416", + "HttpRequestNumber":4, + "HttpSessionId":"0cea7395-ba29-e6c6-93ee-7c08a2fd7219" +} +``` + +To learn more about structured logging and message templates you can read more about it over on the [https://messagetemplates.org](https://messagetemplates.org) website. Alternatively watch this video from the Serilog creator - [https://www.youtube.com/watch?v=OhmNp8UPEEg](https://www.youtube.com/watch?v=OhmNp8UPEEg) + +## Writing to the log + +Umbraco writes log messages, but you are also able to use the Umbraco logger to write the log file as needed. This allows you to gain further insights and details about your implementation. + +Here is an example of using the logger to write an Information message to the log. It will contain one property, **Name**, which will output the name variable that is passed into the method. + +```csharp +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace Umbraco.Cms.Web.UI.NetCore; + +[ApiController] +[Route("/umbraco/api/myapi")] +public class MyApiController : Controller +{ + private readonly ILogger _logger; + + public MyApiController(ILogger logger) + { + _logger = logger; + } + + /// /umbraco/api/MyApi/SayHello?name=John + [HttpGet("sayhello")] + public string SayHello(string name) + { + _logger.LogInformation("We are saying hello to {Name}", name); + return $"Hello {name}"; + } +} +``` + +{% hint style="info" %} +If you are Logging and using the MiniProfiler, you can inject `IProfilingLogger` that has a reference to both ILogger and IProfiler. +{% endhint %} + +The incorrect way to log the message would be use string interpolation or string concatenation such as + +```csharp +//GOOD - Do use :) +_logger.LogInformation("We are saying hello to {Name}", name); + +//BAD - Do not use :( +_logger.LogInformation($"We are saying hello to {name}"); + +//BAD - Do not use :( +_logger.LogInformation("We are saying hello to " + name); +``` + +The bad examples above will write to the log file, but we will not get a separate property logged with the message. This means we can't find them by searching for log messages that use the message template `We are saying hello to {Name}` + +## Log Levels + +Serilog uses levels as the primary means for assigning importance to log events. The levels in increasing order of importance are: + +1. **Verbose** - tracing information and debugging minutiae; generally only switched on in unusual situations +2. **Debug** - internal control flow and diagnostic state dumps to facilitate pinpointing of recognised problems +3. **Information** - events of interest or that have relevance to outside observers; the default enabled minimum logging level +4. **Warning** - indicators of possible issues or service/functionality degradation +5. **Error** - indicating a failure within the application or connected system +6. **Fatal** - critical errors causing complete failure of the application + +## Configuration + +Serilog can be configured and extended by using the .NET Core configuration such as the AppSetting.json files or environment variables. For more information, see the [Serilog config](../../../reference/configuration/serilog.md) article. + +## The UmbracoFile Sink + +Serilog uses the concept of Sinks to output the log messages to different places. Umbraco ships with a custom sink configuration called UmbracoFile that uses the [Serilog.Sinks.File](https://github.com/serilog/serilog-sinks-file) sink. This will save the logs to a rolling file on disk. You can disable this sink by setting its Enabled configuration flag to false, see [Serilog config](../../../reference/configuration/serilog.md) for more information. + +## The logviewer dashboard + +Learn more about the [logviewer dashboard](../../backoffice/logviewer.md) in the backoffice and how it can be extended. + +## The logviewer desktop app + +This is a tool for viewing & querying JSON log files from disk in the same way as the built in log viewer dashboard. + +[![English badge](https://developer.microsoft.com/store/badges/images/English\_get-it-from-MS.png)](https://www.microsoft.com/store/apps/9N8RV8LKTXRJ?cid=storebadge\&ocid=badge) + +## Serilog project/references shipped + +Umbraco ships with the following Serilog projects, where you can find further information & details with the GitHub readme files as needed. + +* [Serilog](https://github.com/serilog/serilog) +* [Serilog.AspNetCore](https://github.com/serilog/serilog-aspnetcore) +* [Serilog.Enrichers.Process](https://github.com/serilog/serilog-enrichers-process) +* [Serilog.Enrichers.Thread](https://github.com/serilog/serilog-enrichers-thread) +* [Serilog.Expressions](https://github.com/serilog/serilog-expressions) +* [Serilog.Formatting.Compact](https://github.com/serilog/serilog-formatting-compact) +* [Serilog.Formatting.Compact.Reader](https://github.com/serilog/serilog-formatting-compact-reader) +* [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration) +* [Serilog.Sinks.Console](https://github.com/serilog/serilog-sinks-console) +* [Serilog.Sinks.File](https://github.com/serilog/serilog-sinks-file) + +## Further Resources + +If you are interested in learning more then the following resources will beneficial: + +* [Serilog](https://serilog.net/) +* [Serilog Community Gitter Chatroom](https://gitter.im/serilog/serilog) +* [Nicholas Blumhardt Blog, creator of Serilog](https://nblumhardt.com/) +* [Serilog Pluralsight Course](https://www.pluralsight.com/courses/modern-structured-logging-serilog-seq) +* [Seq](https://getseq.net/) This is **free** for a single machine such as your own local development computer diff --git a/17/umbraco-cms/fundamentals/code/images/app-data-folders-version8.png b/17/umbraco-cms/fundamentals/code/images/app-data-folders-version8.png new file mode 100644 index 00000000000..cc29d42414f Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/app-data-folders-version8.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/app-data-folders.png b/17/umbraco-cms/fundamentals/code/images/app-data-folders.png new file mode 100644 index 00000000000..dee62c605f5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/app-data-folders.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/file-structure-v10.png b/17/umbraco-cms/fundamentals/code/images/file-structure-v10.png new file mode 100644 index 00000000000..afc7495f8a7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/file-structure-v10.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/folder-structure-v9.jpg b/17/umbraco-cms/fundamentals/code/images/folder-structure-v9.jpg new file mode 100644 index 00000000000..71612ed5203 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/folder-structure-v9.jpg differ diff --git a/17/umbraco-cms/fundamentals/code/images/log-message.png b/17/umbraco-cms/fundamentals/code/images/log-message.png new file mode 100644 index 00000000000..a14351f98d1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/log-message.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/log-messages-v14.png b/17/umbraco-cms/fundamentals/code/images/log-messages-v14.png new file mode 100644 index 00000000000..b1d64325736 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/log-messages-v14.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/log-messages.png b/17/umbraco-cms/fundamentals/code/images/log-messages.png new file mode 100644 index 00000000000..ce3872a7669 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/log-messages.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/log-viewer-v14.png b/17/umbraco-cms/fundamentals/code/images/log-viewer-v14.png new file mode 100644 index 00000000000..c0724c980d0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/log-viewer-v14.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/log-viewer.png b/17/umbraco-cms/fundamentals/code/images/log-viewer.png new file mode 100644 index 00000000000..d2010ec4570 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/log-viewer.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders-version8.png b/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders-version8.png new file mode 100644 index 00000000000..0ddebc9768e Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders-version8.png differ diff --git a/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders.png b/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders.png new file mode 100644 index 00000000000..87561e23c53 Binary files /dev/null and b/17/umbraco-cms/fundamentals/code/images/typical-umbraco-project-folders.png differ diff --git a/17/umbraco-cms/fundamentals/code/source-control.md b/17/umbraco-cms/fundamentals/code/source-control.md new file mode 100644 index 00000000000..7b78737f58a --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/source-control.md @@ -0,0 +1,148 @@ +--- +description: >- + In this article you can learn more about how to effectively source control + your Umbraco site. +--- + +# Source Control + +## Umbraco Cloud + +When you are running your site on Umbraco Cloud, source control is a part of the experience. Have a look at the ['Technical overview of an Umbraco Cloud Environment'](https://docs.umbraco.com/umbraco-cloud/getting-started/environments) and the information on ['Working with your Umbraco Cloud project'](https://docs.umbraco.com/umbraco-cloud/setup/set-up#working-with-your-umbraco-cloud-project) for a steer on Source/Version Control good practices. + +## Outside of Umbraco Cloud + +If you are hosting your Umbraco implementation outside of Umbraco Cloud, it's generally considered good practice to set up source/version control for your site implementation files. This is especially a good idea when you are working with a team as it can help you track changes and manage conflicts with other developer's work. + +So if you've made the decision to try to attempt to source/version control your Umbraco implementation work, perhaps setting up a ['Git Repository'](https://en.wikipedia.org/wiki/Git) - then a frequently asked question is: + +### What folders and files should I **exclude** from my source control repository? + +There are lots of different possible variations within your working environment that will affect the best way to set up version control. It depends on whether you are: + +* Working with a team of developers. +* How your development environment is set up. +* Source control repository. +* And also how you intend to build and deploy your solution to your target production environment (build servers, Web Deploy or good old File Transfer Protocol (FTP), etc). + +However, Umbraco ships with a `.gitignore` file with a custom Umbraco section, which will make git ignore the files for you. The Umbraco specific section looks like this: + +``` +## +## Umbraco CMS +## + +# JSON schema file for appsettings.json +appsettings-schema.json + +# Packages created from the backoffice (package.xml/package.zip) +/umbraco/Data/CreatedPackages/ + +# Temp folder containing Examine indexes, MediaCache, etc. +/umbraco/Data/TEMP/ + +# SQLite database files +/umbraco/Data/*.sqlite.db +/umbraco/Data/*.sqlite.db-shm +/umbraco/Data/*.sqlite.db-wal + +# Log files +/umbraco/Logs/ + +# Media files +/wwwroot/media/ +``` + +For most projects, this gitignore will be enough, and this article will not be an exhaustive list of how to version control Umbraco in all possible scenarios. + +However, we will go through the different files in order to give you an insight into the anatomy of an Umbraco website and therefore which parts to include in version control and which parts not to. + +![Typical set of Umbraco Project Folders](../../../../10/umbraco-cms/fundamentals/code/images/file-structure-v10.png) + +#### The Umbraco Folder + +The main folder where the Umbraco CMS resides is the `/umbraco` one inside your project. + +Most of the files and folders within the Umbraco folder, is already added to the default gitignore file. As most of the Umbraco CMS core files are embedded, the `/umbraco` folder contains primarily temporary files and log files, which are all added as Umbraco is installed. + +We recommend that you follow the structure of the default gitignore file, and do not include any temporary files, log files or cache files to git. + +Below are a set of general recommendations regarding the files within the `/umbraco` folder. + +* `/umbraco/data/TEMP` - This folder contains examine indexes, NuCache files, and so on, these are temporary and should not be committed. +* `/umbraco/Logs` - Umbraco currently uses _Serilog_, and a file will be generated in this folder containing trace logs of your application, one JSON file for each day. +* `/umbraco/mediacache` - _ImageSharp_ ships with Umbraco and when an image is requested via the processor, for example, to be resized or cropped, a cached version of the transformed image will be stored in this folder. (The [Imaging settings section](../../reference/configuration/imagingsettings.md) allows you to determine where this cache is stored) + +#### Umbraco Models Builder + +The strategy here will depend a little on which mode ['Umbraco Models Builder'](../../reference/templating/modelsbuilder/) you have opted to work with. + +* **InMemoryAuto** (default), The models are generated in memory, no source control is required. +* **SourceCodeManual** and **SourceCodeAuto**, The models are generated in the `/umbraco/models` folder of your project (or can be configured to be in a different folder or project), allowing you to track changes to the models in source/version control. + +#### Media + +The Media section of Umbraco (unless configured otherwise) stores files in the `/wwwroot/media` folder. These can be updated by editors, in the Umbraco backoffice, so generally speaking, you would not source control these files. + +These are by default ignored by git. + +#### Packages and Plugins + +The **App\_Plugins** folder is the home for all third-party packages installed on your site. + +Depending on how you installed the plugin it will affect how you choose to version control a particular third-party plugin: + +Since plugins are installed via NuGet the installed files for individual plugins shouldn't need to be source controlled (and your deployment process should pull the packages implementation files from NuGet during the build and deployment process). + +{% hint style="info" %} +Each plugin could be different depending on its implementation and functionality. It may contain files that it would be useful to track via Source control, and also files that should be ignored: check with the plugin's supporting website/developer for more information. +{% endhint %} + +### What folders and files should I **include** in my source control repository? + +#### Front-end build + +A lot depends on how you maintain the front-end build of your website, e.g. are you using CSS preprocessors such as Sassy Cascading Style Sheets (SCSS)/ Leaner CSS (LESS) etc - gulp/grunt tasks to combine and minify script resources. + +But generally, you will need to source control all your website's static assets: JavaScript, CSS, Fonts, Page Furniture Images, etc. + +#### Views/Templates/Partials + +Umbraco site templates/views can be edited via the Umbraco Backoffice. They also reside in the `/Views` folder on disk. As these views/templates often include code, it can make a lot of sense to have their changes tracked under source/version control. + +However, this can pose a problem if the templates are updated via the backoffice outside of source control on the production environment. + +This is not an advisable approach since often this will cause breaking changes to your website. + +You would need to manually merge these files before considering a deployment. + +Umbraco Cloud is a good solution in these scenarios, as changes via the backoffice are tracked in a Git repository automatically. + +#### Controllers/Classes/Custom Code + +Any supporting custom code for your application should be in version control, eg any of the following files + +* C# implementation, + * Surface Controllers + * API Controllers + * ViewModels + * Helpers / Extension Methods + * Services etc. +* Supporting class library projects, +* Models generated by Modelsbuilder in SourceCodeManual or SourceCodeAuto mode. + +#### Config + +Your site's `appsettings.json` and `appsettings.Development.json` files contain the configuration for your Umbraco site. + +In general, it is recommended to add these to source control. When you do this, be sure that the file(s) doesn't contain any secrets, like API keys and connection strings. These can be added as needed, but omitted from any commits made to source control. + +#### DocumentType - Backoffice Structure Changes + +When you create and edit eg. Document Types, Media Types, and Data Types in the Umbraco Backoffice these values are stored in the Umbraco Database, making them difficult to source control in a 'file based' version control system. + +There are a series of add-on packages that can help add source control to these structure changes: + +* [_The uSync package (free)_](https://our.umbraco.com/projects/developer-tools/usync/) - which can be configured to serialize these changes to files on disk, in a folder called /uSync - enabling you to source/version control these changes and synchronise them to other environments. +* [_uSync Snapshots (licensed)_](https://our.umbraco.com/packages/developer-tools/usyncsnapshots/) - an extension to uSync, for taking 'before' and 'after' snapshots of an Umbraco site, for managing a release of a 'set of changes' between environments. +* [_Umbraco Deploy on Premise_](https://umbraco.com/products/umbraco-deploy/umbraco-deploy-on-premises/) - the on premise version of the package used by Umbraco Cloud. diff --git a/17/umbraco-cms/fundamentals/code/subscribing-to-notifications.md b/17/umbraco-cms/fundamentals/code/subscribing-to-notifications.md new file mode 100644 index 00000000000..f2fbfdc8d12 --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/subscribing-to-notifications.md @@ -0,0 +1,213 @@ +--- +description: >- + Subscribing to notifications allows you to listen to specific events and run custom code in response. +--- + +# Subscribing To Notifications + +Subscribing to notifications allows you to run custom code in response to specific events, such as when the content is created, updated, or deleted. This feature enables you to automate tasks, validate data, log actions, and implement other custom functionalities to enhance your content management system. + +To follow this guide, ensure you have an Umbraco installation with content, such as the Umbraco starter kit. In this article, we will walk you through the process of logging a message every time a document is published in Umbraco. + +## Create a Notification Handler + +We will add a string of text to the log whenever a document is published. This log is useful for debugging, as different parts of the Umbraco codebase log key events, warnings, and errors. + +1. Add a new C# class file to your project. For example: **~/App_Plugins/Notifications/LogWhenPublishedHandler.cs**. +2. Implement the `INotificationHandler` interface to identify this class as a handler for content publication events. +3. Add the following `using` statements at the top of your file: + + ```csharp + using Umbraco.Cms.Core.Events; + using Umbraco.Cms.Core.Notifications; + ``` + +Your class should now look like this: + +{% code title="LogWhenPublishedHandler.cs" overflow="wrap" lineNumbers="true" %} + +```csharp +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; + +namespace MyProject; + +public class LogWhenPublishedHandler : INotificationHandler +{ + // Here we will handle a notification. +} +``` + +{% endcode %} + +## Implement the Handle Method + +The `INotificationHandler` interface requires a `Handle` method to be implemented. + +Use the code snippet below to implement the `Handle` method, which takes a `ContentPublishedNotification` parameter. This method will contain the custom logic that runs after content is published. + +{% code title="LogWhenPublishedHandler.cs" overflow="wrap" lineNumbers="true" %} + +```csharp +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; + +namespace MyProject; + +public class LogWhenPublishedHandler : INotificationHandler +{ + public void Handle(ContentPublishedNotification notification) + { + // The custom code to fire every time content is published goes here! + throw new System.NotImplementedException(); + } +} +``` + +{% endcode %} + +## Inject a Logger for Logging + +To log messages, we need to inject a `Microsoft ILogger` into the handler. + +1. Add a `using` statement for the `Microsoft.Extensions.Logging` namespace to your file. +2. Add a constructor to the handler class that accepts an `ILogger` instance. + +Your updated class should look like this: + +{% code title="LogWhenPublishedHandler.cs" overflow="wrap" lineNumbers="true" %} + +```csharp +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; + +namespace MyProject; + +public class LogWhenPublishedHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public LogWhenPublishedHandler(ILogger logger) + { + _logger = logger; + } + + public void Handle(ContentPublishedNotification notification) + { + // The custom code to fire every time content is published goes here! + throw new System.NotImplementedException(); + } +} +``` + +{% endcode %} + +## Log the Content Publication + +Now that we have a logger, let us use it to log a message every time content is published. + +Use the code snippet below to replace the `NotImplementedException` with the code that logs the publication event. + +{% code title="LogWhenPublishedHandler.cs" overflow="wrap" lineNumbers="true" %} + +```csharp +public void Handle(ContentPublishedNotification notification) +{ + // The custom code to fire every time content is published goes here! + _logger.LogInformation("Something has been published."); + foreach (var publishedItem in notification.PublishedEntities) + { + _logger.LogInformation("{ContentName} was published", publishedItem.Name); + } +} +``` + +{% endcode %} + +
+ +See the entire handler class: LogWhenPublishedHandler.cs + +{% code title="LogWhenPublishedHandler.cs" overflow="wrap" lineNumbers="true" %} + +```csharp +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; + +namespace MyProject; + +public class LogWhenPublishedHandler : INotificationHandler +{ + private readonly ILogger _logger; + + public LogWhenPublishedHandler(ILogger logger) + { + _logger = logger; + } + + public void Handle(ContentPublishedNotification notification) + { + _logger.LogInformation("{ContentName} was published", publishedItem.Name); + } +} +``` + +{% endcode %} + +
+ +## Register the Notification Handler + +Umbraco needs to know that our handler exists and that it handles `ContentPublishedNotification`. We need to register it in the **Program.cs** file. + +{% hint style="info" %} +Registering dependencies and extensions like this can be done using different methods. Which method to use in each situation depends on whether the extension is added to the Umbraco site or a package. + +Learn more about registering dependencies in the [Dependency Injection](../../reference/using-ioc.md) article. +{% endhint %} + +1. Open the **Program.cs** file at the root of the project. +2. Add the `using Umbraco.Cms.Core.Notifications;` statement. + + ```csharp + using Umbraco.Cms.Core.Notifications; + ``` + +3. Register the handler in the builder configuration by adding the `.AddNotificationHandler()` method call. + + The registration should look like this: + + ```csharp + builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddNotificationHandler() + .Build(); + ``` + +## Publishing Content and Verifying Custom Log Messages + +1. Access the Umbraco backoffice and publish a piece of content. +2. Check the log messages in the **Log Viewer** under the **Settings** section. + + ![Log Viewer](images/log-viewer-v14.png) + +3. Search **All Logs**. + +If everything is set up correctly you will see your custom log messages. + +![Messages in Log](images/log-messages-v14.png) + +## Additional Notes + +* The code in this article logs a message after content is published because we subscribed to `ContentPublishedNotification`. +* If you need to run code before content is published, you can subscribe to `ContentPublishingNotification` instead. +* This pattern applies to other events as well, such as **Saving**, **Saved**, **Copying**, **Copied** and so on. + +## More Information + +* For further details on Notifications in Umbraco, see the [Using Notifications](../../reference/notifications/README.md) article. diff --git a/17/umbraco-cms/fundamentals/code/umbraco-services.md b/17/umbraco-cms/fundamentals/code/umbraco-services.md new file mode 100644 index 00000000000..6dec1faf221 --- /dev/null +++ b/17/umbraco-cms/fundamentals/code/umbraco-services.md @@ -0,0 +1,221 @@ +# Service APIs + +_Whenever you need to modify an entity that Umbraco stores in the database, there are service APIs available to help you. This means that you can create, update and delete any of the core Umbraco entities directly from your custom code._ + +## Accessing the Umbraco services + +Services are typically defined using interfaces. Umbraco has them in the `Umbraco.Cms.Core.Services` namespace, while the specific implementations can be found under the `Umbraco.Cms.Core.Services.Implement` namespace. To use the service APIs you must first access them. Owing to the built-in dependency injection (DI) in ASP.NET Core, configured services are made available throughout Umbraco's codebase. This can be achieved via injecting the specific service you require - the service type or an interface. + +### Access via a Controller + +If you are accessing Umbraco services inside your own controller class, you can add the Umbraco services that you need as constructor parameters. An instance of every service will be provided at runtime from the service container. By saving each one to a local field, you can make use of them within the scope of your class: + +```csharp +public class CustomController +{ + private readonly IContentService _contentService; + + + public ContentController(IContentService contentService) + { + _contentService = contentService; + } + + + public ActionResult PerformAction() + { + var someContent = _contentService.GetById(1234); + } +} +``` + +### Access via a Razor View Template + +Inside a Razor View template, you can make use of a service injection into a view using the `@inject` directive. It works similarly to adding a property to the view, and populating the property using DI: + +```csharp +@using Umbraco.Cms.Core.Services +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@inject IPublicAccessService PublicAccessService +@{ + Layout = "master.cshtml"; + bool isPageProtected = PublicAccessService.IsProtected(Model.Path); +} +@if (isPageProtected) +{ +

Secret Page - shhshshsh!

+} +``` + +### Access in a Custom Class via dependency injection + +If we wish to subscribe to notifications on one of the services, we'd create a Composer C# class, where you will add a custom `NotificationHandler`. In this custom `NotificationHandler` we would inject the service we need into the public constructor of the class and Umbraco's. The underlying dependency injection framework will do the rest. + +In this example we will wire up to the ContentService 'Saved' event. We will create a new folder in the Media section whenever a new LandingPage is created in the content section to store associated media. Therefore we will need the MediaService available to create the new folder. + +```csharp +public class CustomComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + } +} +``` + +```csharp +using System.Linq; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Core.Events; + +public class CustomNotificationHandler : INotificationHandler +{ + // access to the MediaService by injection + private readonly IMediaService _mediaService; + private readonly IRuntimeState _runtimeState; + + public CustomNotificationHandler(IMediaService mediaService, IRuntimeState runtimeState) + { + _mediaService = mediaService; + _runtimeState = runtimeState; + } + + public void Handle(ContentSavedNotification notification) + { + if (_runtimeState.Level != RuntimeLevel.Run) + { + return; + } + + foreach (var contentItem in notification.SavedEntities) + { + // if this is a new landing page create a folder for associated media in the media section + if (contentItem.ContentType.Alias == "landingPage") + { + // we have injected in the mediaService in the constructor for the component see above. + bool hasExistingFolder = _mediaService.GetByLevel(1).Any(f => f.Name == contentItem.Name); + if (!hasExistingFolder) + { + // let's create one (-1 indicates the root of the media section) + IMedia newFolder = _mediaService.CreateMedia(contentItem.Name, -1, "Folder"); + _mediaService.Save(newFolder); + } + } + } + } +} +``` + +#### Custom Class example + +When you're creating your own class, in order to make use of the dependency injection framework, you need register the `ICustomNewsArticleService` service with the type `CustomNewsArticleService`. The `AddScoped()` method registers the service with the lifetime of a single request. + +There are different ways that you can achieve the same outcome: + +Register directly into the **Program.cs** class. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .Build(); + +builder.Services.AddScoped(); +``` + +Another approach is to create an extension method to `IUmbracoBuilder` and add it to the startup pipeline. + +```csharp +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; + +namespace DefaultNamespace; + +public static class UmbracoBuilderServiceExtensions +{ + public static IUmbracoBuilder AddCustomServices(this IUmbracoBuilder builder) + { + builder.Services.AddScoped(); + + return builder; + } +} +``` + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddCustomServices() + .Build(); +``` + +When creating Umbraco packages you don't have access to the Startup class, therefore it's recommended to use a `IComposer` instead. A Composer gives you access to the `IUmbracoBuilder`. + +If you don't have access to the Startup class + +```csharp +public class CustomComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Services.AddScoped(); + } +} +``` + +Then your custom class eg. `CustomNewsArticleService` can take advantage of the same injection to access services eg: + +```csharp +using System.Linq; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; + +namespace Umbraco.Cms.Infrastructure.Services.Implement; + +public class CustomNewsArticleService: ICustomNewsArticleService +{ + private readonly IMediaService _mediaService; + private readonly ILogger _logger; + private readonly IUmbracoContextFactory _contextFactory; + + public CustomNewsArticleService(ILogger logger, IUmbracoContextFactory contextFactory, IMediaService mediaService) + { + _logger = logger; + _contextFactory = contextFactory; + _mediaService = mediaService; + } + + public void DoSomethingWithNewsArticles() + { + using (var contextReference = _contextFactory.EnsureUmbracoContext()) + { + IPublishedContentCache contentCache = contextReference.UmbracoContext.Content; + IPublishedContent newsSection = contentCache.GetAtRoot().FirstOrDefault().Children().FirstOrDefault(f => f.ContentType.Alias == "newsSection"); + if (newsSection == null) + { + _logger.LogDebug("News Section Not Found"); + } + } + // etc + } +} +``` + +### More information + +* [Services in Umbraco](../../reference/management/) +* [Umbraco Notifications reference](../../reference/notifications/) +* [Routes and controllers](../../reference/routing/) diff --git a/17/umbraco-cms/fundamentals/data/README.md b/17/umbraco-cms/fundamentals/data/README.md new file mode 100644 index 00000000000..b3a0948ea0b --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/README.md @@ -0,0 +1,55 @@ +--- +description: This section focuses on how to create data using the Umbraco backoffice +--- + +# Data + +_This section focuses on how to create data using the Umbraco backoffice._ + +There are three kinds of content in Umbraco: + +* Your normal website content exists in the content section. +* Media content such as images, videos, and PDFs are stored in the Media section. +* Finally, Members, are used for user profiles and frontend authentication which you can find in the Members section. + +A fundamental principle in Umbraco is that all content types have a definition (Document Types, Media Types, Member Types). These definitions are highly customizable, meaning you can add properties and have complete control over how the data is organized. + +## [Defining Content](defining-content/) + +Defining Document Types, adding properties, and creating content. + +## [Creating Media](creating-media/) + +Defining Media Types and uploading files to the media section, using upload fields and image cropper. + +## [Creating Members](members.md) + +Defining Member Types and creating members for authentication and user profiles. + +## [Customizing Data Types](data-types/) + +Creating and editing Data Types. + +## [Scheduled Publishing](scheduled-publishing.md) + +Schedule when content should be published / unpublished automatically. + +## [Adding Tabs](adding-tabs.md) + +Overview of how to add and reorder tabs, convert a group to a tab, and manage the “Generic” tab + +## [Users](users/) + +Control who has access to the Umbraco backoffice and what permissions they have. + +## [Relations](relations.md) + +An introduction to Relations and Relation Types, creating, and managing relationships between different entities in Umbraco. + +## [Dictionary Items](dictionary-items.md) + +Using Dictionary Items, you can store a value for each language. Dictionary Items have a unique key that is used to fetch the value of the Dictionary Item. + +## [Content Version Cleanup](content-version-cleanup.md) + +How to keep the noise down whilst ensuring your important content versions stick around indefinitely. diff --git a/17/umbraco-cms/fundamentals/data/adding-tabs.md b/17/umbraco-cms/fundamentals/data/adding-tabs.md new file mode 100644 index 00000000000..b998fa4e8e6 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/adding-tabs.md @@ -0,0 +1,64 @@ +# Using Tabs + +In this section, an overview is given of how to add and reorder tabs, convert a group to a tab and manage the “Generic” tab. + +## Adding a tab + +Using tabs, you can organize properties in the backoffice to provide a tailored and efficient workflow for editors creating and maintaining Content, Media and Members. + +Tabs allow you to add horizontal organization in your Document Types, Media Types and Member Types. This is handy for types that need a more defined hierarchy or have many properties and groups. + +To add a tab, follow these steps: + +1. Go to **Settings**. +2. Create or select a **Document Type/Media Type/Member Type** and click **Add tab**. + + ![Add tab](images/Add-tab.png.png) + +{% hint style="info" %} +When adding the first tab, all existing groups are automatically added to the tab. +{% endhint %} + +## Reordering tabs + +To reorder tabs, follow these steps: + +1. Go to **Settings**. +2. Select a **Document Type/Media Type/Member Type**. +3. Select **Reorder**. +4. You can drag the tab where you want, manually add a numeric value next to the tab name or use the arrows to set a value. + + This is important when using compositions, as you want to always display a tab/group at a certain position by setting a manual numeric value. + + ![Reorder tabs](images/Reorder-tabs.gif) +5. Select **I am done reordering**. +6. Click **Save**. + +## Convert a group to a tab + +To convert a group to a tab, follow these steps: + +1. Go to **Settings**. +2. Select a **Document Type/Media Type/Member Type**. +3. Select **Reorder**. +4. You can drag the group to the **Convert to tab** option. +5. Select **I am done reordering**. +6. Click **Save**. + +{% hint style="info" %} +Converting a tab back into a group is not possible, as tabs can contain groups, and nested groups are unsupported. To overcome this, create a new group and transfer all tab properties into it, then delete the empty tab. +{% endhint %} + +## Managing the “Generic” tab + +Once you start adding tabs, you might see a “Generic” tab appear. This is done to hold groups and properties that are not assigned to a tab. For example, a group of properties coming from a composition that has no tab. In order to display the groups and properties correctly and have a solid data structure, they will be displayed under the “Generic” tab. + +![Generic-tab](images/Generic-tab.png) + +To manage the **Generic** tab on a **Document Type/Media Type**: + +1. Go to the **Composition** Document Type/Media Type. +2. Click **Add tab** and enter the **Name** for the tab. All existing groups and properties are added to the tab. +3. Go to the **Document Type/Media Type**, the **Generic** tab will now be replaced by the tab from the composition. + + ![Composition Add Tab](images/Composition-add-tab.gif) diff --git a/17/umbraco-cms/fundamentals/data/content-version-cleanup.md b/17/umbraco-cms/fundamentals/data/content-version-cleanup.md new file mode 100644 index 00000000000..9cd7197359b --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/content-version-cleanup.md @@ -0,0 +1,64 @@ +# Content Version Cleanup + +A new version is created whenever you save and publish a content item in Umbraco. This is how you can roll back to a previous version. Every saved version stores a record in the database, not only for the version but also for each content item property for that version. In a multi-lingual site, further rows are added for every culture variation. Over time this amount of data can build and swallow up the capacity of your SQL Server and slow the performance of the Umbraco backoffice. + +## How it works + +The default cleanup policy will: + +* Not delete any versions created over the previous 4 days. The recent version history is preserved. See the `KeepAllVersionsNewerThanDays` setting. +* 'Prune' versions 4 days after they are created. The last version of a content item saved on a particular day will be kept but earlier versions from that day will be deleted. +* Delete all versions older than 90 days. See the `KeepLatestVersionPerDayForDays` setting. +* Never delete any versions that are currently 'published'. +* Never delete any specific versions marked as 'Prevent Cleanup' in the Backoffice version history. + +{% hint style="info" %} + +Based on the default cleanup policy, you can roll back content to the latest version saved on a particular day as long as it was + +* Created within the last 90 days, or +* Marked as "Prevent Cleanup" in the Backoffice version history. + +The **History** section, which acts as an audit log, is not cleared out, and will continue to show logs for versions older than 90 days. +{% endhint %} + +The feature can be configured in the `appSettings.json`: + +```json +{ + "Umbraco": { + "CMS": { + "Content": { + "ContentVersionCleanupPolicy": { + "EnableCleanup": true, + "KeepLatestVersionPerDayForDays": 90, + "KeepAllVersionsNewerThanDays": 4 + } + } + } + } +} +``` + +For sites with stricter requirements, it is possible to opt-out of both options globally, see [ContentSettings](../../reference/configuration/contentsettings.md#contentversioncleanuppolicy) and by Document Type. + +Additionally, it is possible to keep the feature enabled but mark specific versions to keep forever. + +It is worth noting that whilst we delete rows, we do not shrink database files or rebuild indexes. For upgraded sites with a lot of history you may wish to perform these tasks. If they are not part of your regular database maintenance plan already. + +## Overriding global settings + +It is possible to override the global settings per Document Type in the backoffice to prevent unwanted cleanup. This can be managed in the "permissions" Content App for each Document Type. + +
Content Version Cleanup - Document Type overrides

Content Version Cleanup - Document Type overrides

+ +## Prevent cleanup of important versions + +It is possible to mark important content versions as "prevent cleanup" to ensure they are never removed. This happens via the new and improved rollback modal which can be found on the "info" content app for each document. + +1. Open rollback modal. + +
+2. Click **Prevent cleanup** button for each important version. + +
diff --git a/17/umbraco-cms/fundamentals/data/creating-media/README.md b/17/umbraco-cms/fundamentals/data/creating-media/README.md new file mode 100644 index 00000000000..a20a8f0ee47 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/creating-media/README.md @@ -0,0 +1,213 @@ +--- +description: >- + Learn how to work with different types of Media content on your Umbraco + website. +--- + +# Creating Media + +Media in Umbraco CMS is handled the same way as content. You define **Media Types** that act as a base for media items. The following default Media Types are available: + +* Article - used for uploading and storing documents. +* Audio - used for uploading and storing digital audio files. +* File - used for uploading and storing different types of files in the Media section. +* Folder - a container for organizing media items in the Media section tree. +* Image - used for uploading and storing images. +* Vector Graphics (SVG) - used for uploading and storing Scalable Vector Graphics (SVG) files which are text files containing source code to draw the desired image. +* Video - used for uploading and storing video files. + +The default Media Types aim to cover most needs for media on a website. You do not need to define your Media Types to start using the Media section. The tools for organizing and uploading the media are already in place. + +{% hint style="info" %} +If you have upgraded from an older version than 8.14 the Media Types listed above are not added automatically. You can add those types manually yourselves by following the steps below ['Creating a new Media Type'](./#creating-a-media-type). On the [default media types page](default-media-types.md), you will find a detailed overview of all Media Types. +{% endhint %} + +## Uploading Media + +You can upload media in two different ways: + +* [Through the Media section](./#add-media-through-the-media-section) and +* [Through the Content section](./#add-media-through-the-content-section) + +### Add media through the Media section + +From the **Media** section in the Umbraco backoffice, you can add new media items by following either of the approaches defined below: + +* Use the **Create** dialog to create a new Media item in the Media section + + * The Media item will be created based on the type you choose. + * Upload the image or file, give the Media item a name, and click **Save**. + +
Upload Media - Create Button

Upload Media - Create Button

+* Use the Drag and drop feature to add your files to the Media section. + + * Umbraco will automatically detect the Media Type and create the Media item. + * You can drop entire folder structures to recreate that same structure in the Media section. + +
Upload Media - Media section

Upload Media - Media section

+ +### Add media through the Content section + +New media items can be added to your site without interrupting the content creation flow. This can be done following either of the two approaches outlined below. + +* Drag and drop the image(s) from your file explorer directly into the Media Picker property on the Content page. + * Images added this way is automatically added to the user's start node in the Media section of the Umbraco backoffice. + +![Drag and drop images directly into the content](../../../../../10/umbraco-cms/fundamentals/data/creating-media/images/upload-images-from-content.gif) + +* Select the "+" icon to open the "Select media" dialog where you can add images from your file explorer directly or using drag and drop. + +![Add images from the "Select media" dialog](../../../../../10/umbraco-cms/fundamentals/data/creating-media/images/add-image-from-dialog.gif) + +## Creating a folder + +It is always a good idea to start by creating a folder for your media items. It can be a good idea to align these folders with the content on your website. This will give the editors a better overview of the files and enable them to upload media items in the correct place. + +Follow these steps to create a folder in the Media section: + +1. Go to the **Media** section. +2. Select **...** next to **Media**. +3. Select **Create**. +4. Select **Folder**. +5. Enter a name for the folder and select **Save** in the bottom-right corner. + +## Media Type properties + +The **Image** Media Type has 5 properties: **Upload Image**, **Width**, **Height**, **Size**, and **Type**. These are populated once the image is uploaded. The properties can be viewed in the **Media** section and accessed in your Templates. + +Except for the **Folder** Media Type, the other Media Types have 3 properties: **Upload Image**, **Type**, and **Size**. + +Learn more about each Media Type in [the article about default Media Types](default-media-types.md). + +## Organizing and editing media items + +The default view for the Media section is a card view that lets you preview the different files that have been uploaded. + +
Media Section - Cardview

Media Section - Cardview

+ +By selecting multiple media items it is possible to perform bulk operations like moving or deleting the items. + +To edit properties on a single media item, click the name of the item, which you will see once you hover over the item. + +![Edit media item](../../../../../10/umbraco-cms/fundamentals/data/creating-media/images/hover-over.png) + +From the top-right corner of the Media section, you can toggle between the list and grid view. There is also an option to search for the items in the Media section.![Media Section - List view](images/switch-view-v14.png) + +## Using media items in the Content section + +By adding a **Media Picker** property to a Document Type the editor will have the ability to select media items when creating content. + +## Creating a Media Type + +You can create custom Media Types and control the structure of the Media tree as you would with Document Types. This means you can store information that is specific to the media on the item itself. + +### Video tutorial + +{% embed url="https://youtu.be/aS39zygmJcQ" %} +Watch this tutorial and learn how to create your own Media Types in Umbraco CMS. +{% endembed %} + +A Media Type is created in the **Settings** section using the Media Type editor. + +1. Go to the **Settings** section. +2. Click **...** next to **Media Types**. +3. Click **Create** > **New Media Type**. +4. Name the new Media Type **Employee Image**. +5. Choose an icon by selecting the icon left of the name field. + +You will now see the Media Type editor. It is similar to the editor used for creating Document Types. + +![Creating a Media Type](images/create-new-media-type-v14.png) + +{% hint style="info" %} +Having different folders for different Media Types makes it possible to restrict where media items can be created and added. Only allowing PDF uploads in a certain folder and employee images in another make it easier to keep the Media section organized. +{% endhint %} + +### Adding groups + +Before we start adding properties to the Media Type we need to add a group to put these in. + +1. Click on **Add group**. +2. Call the group _Image_. + +### Adding properties + +We need to add the same properties as on the default **Image** Media Type. These are: + +* `umbracoFile` +* `umbracoWidth` +* `umbracoHeight` +* `umbracoBytes` +* `umbracoExtension` + +Follow the steps outlined below to add the properties to the Media Type: + +1. Click **Add property**. +2. Name it _Upload image_. +3. Change the alias to _umbracoFile_. +4. Click **Select property editor**. +5. Select **Image cropper**. +6. Rename the editor _Employee Image Cropper_. +7. Add two new crops called _Thumbnail_ (200px x 350px) and _wideThumbnail_ (350px x 200px). + +![Defining crops](images/new-data-type-v14.png)\ +8\. Click **Save**.\ +9\. Click **Add**.\ +10\. Name the remaining four properties _Width_, _Height_, _Size_, and _Type_, and give them the aliases as mentioned above. They should all use the **Label** editor. + +As mentioned before these properties will automatically be populated once an image has been uploaded. + +![Adding properties](images/finished-new-media-type-v14.png) + +## Defining a Media Type folder + +Next up, we will create a folder to hold the employee images. We could use the existing **Folder** Media Type but that would mean editors can upload employee images to any folder of that type. If we create a folder specifically for employee images there is only one place to put them. + +1. Go back to the **Settings** section and create a new Media Type. +2. Name it _Employee Images_. +3. Select the folder icon by clicking the icon to the left of the name. +4. Navigate to the **Structure** tab. +5. Click **Configure as a Collection** under **Presentation.** +6. Choose **List view - Media.** + +![Configure Collection](images/configure-collection-v14.png)\ +7\. Click **Save**. + +The new folder is created under the Media Types folder. We also need to only allow the Employee Image Media Type in our new folder. Both of these configurations can be set on the **Structure** tab. + +1. Go to the **Structure** tab of the _Employee Images_ folder. +2. Toggle the **Allow at root**. +3. Click **Choose** in the **Allowed Child Node Types**. +4. Select **Employee Image**. +5. Click **Choose**. + +![Permissions](images/employee-images-permissions.png) + +### Creating the folder and media items + +1. Go to the **Media** section. +2. Select **...** next to Media. +3. Click **Create** > **Employee Images** folder.![Employee Images](images/employee-images-folder.png) +4. Name it _Employee Images_. +5. Click **Save**. + +{% hint style="info" %} +Uncheck the **Allow at root** option on the **Employee Images** Media Type to prevent the creation of multiple folders of this type. This will only disable the creation of new ones and not affect existing folders. +{% endhint %} + +### Cropping the images + +If you select an image that has been uploaded to the folder you will see the full image and the two defined crops. + +Moving the focal point circle on the image will update the crops to focus accordingly. You can also edit the individual crops by selecting them and moving the image or adjusting the slider to zoom. + +![Cropping images](images/crops-and-focal-point-geo.png) + +## More information + +* [Rendering Media](../../design/rendering-media.md) +* [Customizing Data Types](../data-types/) + +## Related Services + +* [MediaService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.MediaService.html) diff --git a/17/umbraco-cms/fundamentals/data/creating-media/default-media-types.md b/17/umbraco-cms/fundamentals/data/creating-media/default-media-types.md new file mode 100644 index 00000000000..ceb277862a1 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/creating-media/default-media-types.md @@ -0,0 +1,85 @@ +# Default Data/Media Types + +On this page you will find the media types and Data Types in Umbraco. These types are not created automatically after an upgrade. If you want to use the new types, you can create them yourself. + +{% hint style="info" %} +After upgrading, the default media types are not created automatically. If you create them manually, make sure to: +* Set the permission for each of the media types to **Allow at root**. +* Ensure that the **Folder** media type allows the new media types as children. +{% endhint %} + +## Data Types + +### UploadArticle + +The `UploadArticle` Data Type has the following configuration: + +* Property editor: `FileUpload` +* Accepted file extensions: `pdf`, `docx`, `doc` + +### UploadAudio + +The `UploadAudio` Data Type has the following configuration: + +* Property editor: `FileUpload` +* Accepted file extensions: `mp3`, `weba`, `oga`, `opus` + +### UploadVectorGraphics + +The `UploadVectorGraphics` Data Type has the following configuration: + +* Property editor: `FileUpload` +* Accepted file extensions: `svg` + +### UploadVideo + +The `UploadVideo` Data Type has the following configuration: + +* Property editor: `FileUpload` +* Accepted file extensions: `mp4`, `webm`, `ogv` + +## Media Types + +### UmbracoMediaArticle + +The `UmbracoMediaArticle` media type has the following properties: + +* `umbracoFile` - Upload File +* `umbracoExtension` - Label (string) +* `umbracoBytes` - Label (bigint) + +![MediaArticle](images/umbraco-media-article-media-type.png) + +### UmbracoMediaAudio + +The `UmbracoMediaAudio` media type has the following properties: + +* `umbracoFile` Upload Audio +* `umbracoExtension` Label (string) +* `umbracoBytes` Label (bigint) + +![MediaAudio](images/umbraco-media-audio-media-type.png) + +### UmbracoMediaVectorGraphics + +The `UmbracoMediaVectorGraphics` media type has the following properties: + +* `umbracoFile` - Upload Vector Graphics +* `umbracoExtension` Label (string) +* `umbracoBytes` Label (bigint) + +![MediaVectorGraphics](images/umbraco-media-vector-graphicsmedia-type.png) + +### UmbracoMediaVideo + +The `UmbracoMediaVideo` media type has the following properties: + +* `umbracoFile` - Upload Video +* `umbracoExtension` - Label (string) +* `umbracoBytes` - Label (bigint) + +![MediaVideo](images/umbraco-media-video-media-type.png) + +{% hint style="info" %} +You can also create localization files for Media Types. You can read more about this in the [Document Type Localization](../defining-content/document-type-localization.md) article. +{% endhint %} diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cardview.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cardview.jpg new file mode 100644 index 00000000000..760ac1a7b27 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cardview.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Compositions.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Compositions.jpg new file mode 100644 index 00000000000..6d0052c270c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Compositions.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create-740.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create-740.jpg new file mode 100644 index 00000000000..9668165f375 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create-740.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create.jpg new file mode 100644 index 00000000000..ea2f4646669 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Create.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping-740.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping-740.jpg new file mode 100644 index 00000000000..325f6d4dab8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping-740.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping.jpg new file mode 100644 index 00000000000..e277d81d4a2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Cropping.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops-740.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops-740.jpg new file mode 100644 index 00000000000..71b27a6d46b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops-740.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops.jpg new file mode 100644 index 00000000000..8a4a1048d06 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Crops.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Edit.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Edit.jpg new file mode 100644 index 00000000000..7da4356a08c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Edit.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Icon.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Icon.jpg new file mode 100644 index 00000000000..fdc42003a05 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Icon.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Individual-Crop.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Individual-Crop.jpg new file mode 100644 index 00000000000..5f6b3e3e02f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Individual-Crop.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Listview.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Listview.jpg new file mode 100644 index 00000000000..7ec1eae7dbe Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Listview.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Permissions.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Permissions.jpg new file mode 100644 index 00000000000..56f272424e2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Permissions.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties-740.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties-740.jpg new file mode 100644 index 00000000000..8f4d2600b9c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties-740.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties.jpg new file mode 100644 index 00000000000..04e5f1c43cb Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Properties.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Structure.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Structure.jpg new file mode 100644 index 00000000000..b8262a0c516 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Structure.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Tabs.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Tabs.jpg new file mode 100644 index 00000000000..2eae88d1ce0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Tabs.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload-740.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload-740.jpg new file mode 100644 index 00000000000..844927c090c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload-740.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload.jpg b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload.jpg new file mode 100644 index 00000000000..9db5ba2901e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/Creating-Media-Upload.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/add-image-from-dialog.gif b/17/umbraco-cms/fundamentals/data/creating-media/images/add-image-from-dialog.gif new file mode 100644 index 00000000000..1b44a15a995 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/add-image-from-dialog.gif differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/configure-collection-v14.png b/17/umbraco-cms/fundamentals/data/creating-media/images/configure-collection-v14.png new file mode 100644 index 00000000000..bdc9ac877de Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/configure-collection-v14.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-employee.png b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-employee.png new file mode 100644 index 00000000000..0290519affc Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-employee.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type-v14.png b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type-v14.png new file mode 100644 index 00000000000..c553d42cca0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type-v14.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type.png new file mode 100644 index 00000000000..34f39e79ed6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type_new.png b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type_new.png new file mode 100644 index 00000000000..26023a71cbd Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/create-new-media-type_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/crops-and-focal-point-geo.png b/17/umbraco-cms/fundamentals/data/creating-media/images/crops-and-focal-point-geo.png new file mode 100644 index 00000000000..ba6a9b601e5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/crops-and-focal-point-geo.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-folder.png b/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-folder.png new file mode 100644 index 00000000000..f1e09a83d86 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-folder.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-permissions.png b/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-permissions.png new file mode 100644 index 00000000000..fd2bb2ffdb3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/employee-images-permissions.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/enable-listview.png b/17/umbraco-cms/fundamentals/data/creating-media/images/enable-listview.png new file mode 100644 index 00000000000..790ff9c94ba Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/enable-listview.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type-v14.png b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type-v14.png new file mode 100644 index 00000000000..7ae7b5eb115 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type-v14.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type.png new file mode 100644 index 00000000000..8ae9b33a6bc Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type_new.png b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type_new.png new file mode 100644 index 00000000000..f90a6f93128 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/finished-new-media-type_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition.png b/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition.png new file mode 100644 index 00000000000..84dba14eb8c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition_new.png b/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition_new.png new file mode 100644 index 00000000000..e3a64d14060 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/folder-composition_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/four-ways-of-uploading.png b/17/umbraco-cms/fundamentals/data/creating-media/images/four-ways-of-uploading.png new file mode 100644 index 00000000000..7695490160b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/four-ways-of-uploading.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/hover-over.png b/17/umbraco-cms/fundamentals/data/creating-media/images/hover-over.png new file mode 100644 index 00000000000..5e5a75ec5d7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/hover-over.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/media-section-11.png b/17/umbraco-cms/fundamentals/data/creating-media/images/media-section-11.png new file mode 100644 index 00000000000..a2f9502fd60 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/media-section-11.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type-v14.png b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type-v14.png new file mode 100644 index 00000000000..f3d1ddd61d8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type-v14.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type.png new file mode 100644 index 00000000000..33d36cfec27 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type_new.png b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type_new.png new file mode 100644 index 00000000000..5a923f881b0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/new-data-type_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/select-child-nodes.png b/17/umbraco-cms/fundamentals/data/creating-media/images/select-child-nodes.png new file mode 100644 index 00000000000..3ac9bda9788 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/select-child-nodes.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-11.png b/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-11.png new file mode 100644 index 00000000000..ec998111774 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-11.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-v14.png b/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-v14.png new file mode 100644 index 00000000000..6fbc1af8ed8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/switch-view-v14.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/toggle-listview.png b/17/umbraco-cms/fundamentals/data/creating-media/images/toggle-listview.png new file mode 100644 index 00000000000..daa898459a7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/toggle-listview.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-article-media-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-article-media-type.png new file mode 100644 index 00000000000..fff82eeba5b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-article-media-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-audio-media-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-audio-media-type.png new file mode 100644 index 00000000000..194c4dc201a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-audio-media-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-vector-graphicsmedia-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-vector-graphicsmedia-type.png new file mode 100644 index 00000000000..e5957f78e79 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-vector-graphicsmedia-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-video-media-type.png b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-video-media-type.png new file mode 100644 index 00000000000..a0cdd81bcf0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/umbraco-media-video-media-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/upload-images-from-content.gif b/17/umbraco-cms/fundamentals/data/creating-media/images/upload-images-from-content.gif new file mode 100644 index 00000000000..9ffe47785c5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/upload-images-from-content.gif differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-create1.png b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-create1.png new file mode 100644 index 00000000000..5ae33eb69c7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-create1.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-media-section.png b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-media-section.png new file mode 100644 index 00000000000..fc4077de8b6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-media-section.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-upload-media.png b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-upload-media.png new file mode 100644 index 00000000000..c2f0750f6df Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types-upload-media.png differ diff --git a/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types.png b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types.png new file mode 100644 index 00000000000..db993c3f1e7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/creating-media/images/v9-media-types.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/README.md b/17/umbraco-cms/fundamentals/data/data-types/README.md new file mode 100644 index 00000000000..f9ce2a8d302 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/data-types/README.md @@ -0,0 +1,69 @@ +--- +description: Learn about the data types in Umbraco. +--- + +# Data Types + +_A Data Type defines the type of input for a property. So when adding a property (on Document Types, Media Types and Members) and selecting the Type you are selecting a Data Type. There are preconfigured Data Types available in Umbraco and more can be added in the Settings section._ + +## What is a Data Type? + +A Data Type can be something basic such as TextString, Number, True/False and so on. Or it can be more complex such as Multi Node Tree Picker, Image Cropper, Block Grid and so on. + +The Data Type references a Property Editor and if the Property Editor has settings these are configured on the Data Type. This means you can have multiple Data Types referencing the same Property Editor. + +An example of this could be to have two dropdown Data Types both referencing the same dropdown Property Editor. One configured to show a list of cities, the other a list of countries. + +## Creating a new Data Type + +Follow these steps to create a new Dropdown Data Type: + +1. Go to the **Settings** section within the backoffice. +2. Select the **+** icon to the right of the **Data Types** folder. +3. Choose **New Data Type...**. +4. Name the Data Type. +5. Click on **Select a property editor**. +6. Find and click on the **Dropdown** editor. +7. Click **Select**. +8. Choose whether to enable multiple selections. +9. Add **options**. +10. **Save** the Data Type once you have added the required configuration. + +![Dropdown List](images/dropdown-data-type-sample.png) + +{% hint style="info" %} +**Data Type configuration** + +**Property Editor** This is where you pick the Property Editor UI that the Data Type will be referencing. By default, Umbraco ships with a wide selection to choose from. Learn more about each of them in the [Default Data Types](default-data-types.md) article. + +In the **Settings** box below, the configuration options specific to the chosen Property Editor UI will be available. Some Property Editors have many configuration options while some only have a few. +{% endhint %} + +When you're happy with the list press **Save**. It is now possible to select this Data Type for a property on Document Types, Media Types, and Members. Doing this will then create a dropdown list for the editor to choose from and save the choice as a string. + +## Customizing Data Types + +To customize an existing Data Type go to the **Settings** section, expand the **Data Types** folder and select the **Data Type** you want to edit. + +Besides the Data Types that are available out of the box there are some additional **Property Editors**. For example, think of the **Slider** and **Block List**. + +## Viewing Data Type References + +To view the Data Type reference, go to the **Settings** section and expand the **Data Types** folder. Select the **Data Type** you wish to view the reference for and click the **Info** tab. + +![Content Picker References](../../../../../10/umbraco-cms/fundamentals/data/data-types/images/viewing-data-type-reference.png) + +This gives you an overview of the Types that currently use the Data Type. + +Learn more about viewing references or implementing tracking in the [Tracking References](../../../customizing/property-editors/tracking.md) article. + +### More information + +* [List of available Data Types](default-data-types.md) +* [Property Editors](../../backoffice/property-editors/) + +### Related Services + +* [DataTypeService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.IDataTypeService.html) + +### Umbraco Learning Base Channel diff --git a/17/umbraco-cms/fundamentals/data/data-types/default-data-types.md b/17/umbraco-cms/fundamentals/data/data-types/default-data-types.md new file mode 100644 index 00000000000..8c9678065f3 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/data-types/default-data-types.md @@ -0,0 +1,132 @@ +--- +description: Learn about the default data types in Umbraco. +--- + +# Default Data Types + +Here's a list of the default Data Types that come installed with Umbraco. There are plenty more that you can create based on the installed [Property Editors](../../backoffice/property-editors/). + +![Umbraco Data Type List](../../../../../10/umbraco-cms/fundamentals/data/data-types/images/default-data-types-9.png) + +## Approved Color + +Adds a list of approved colors. The approved colors are added as hex values by using the color picker. Optionally, you can enable labels to give the colors different names. + +## Checkbox List + +Displays a list of preset options as a list of checkbox controls. The preset options are added when configuring a Property Editor using the Data Type. Alternatively, the options can also be updated in the **Settings** section under **Data Types**. The value saved is a comma-separated string of IDs. + +## Content Picker + +The Content Picker opens a modal to pick a specific page from the content structure. The value saved is the selected page's ID. + +## Date Picker + +Displays a calendar UI for selecting date and time. The value saved is a standard DateTime value but does not contain time information. + +## Date Picker with time + +Displays a calendar UI for selecting date and time. The value saved is a standard DateTime value. + +## Dropdown + +Displays a list of preset options as a list where only a single value can be selected. The default Data Type does not contain any predefined options. The value saved is the selected value as a string. + +## Dropdown multiple + +Displays a list of preset options as a list where multiple values can be selected. The default Data Type does not contain any predefined options. The value saved is a comma-separated string of IDs. + +## Image Cropper + +Allows to upload and crop images by using a focal point. Specific crop definitions can also be added. This Data Type is used by default on the Image Media Type. + +## Image Media Picker + +The Image Media Picker opens a modal to pick images from the **Media** tree or images from your Computer. The value saved is the selected media node UDI. + +## Label + +Is a non-editable control and can be used to _only_ display the value. It can also be used in the **Media** section to load in values related to the node, such as width, height and file size. + +There are six Label Data Types: + +* Label (bigint) - Allows to save a big integer value for a Label. +* Label (datetime) - Allows to set a DateTime value for a Label. +* Label (decimal) - Allows to set a decimal value for a Label. +* Label (integer) - Allows to set an integer value for a Label. +* Label (string) - Allows to set a long string value for a Label. +* Label (time) - Allows to set time for a Label + +## List View - Content + +This Data Type is used by **Document Types** that are set to display as a Collection. + +## List View - Media + +This Data Type is used by **Media Types** that is set to display as a Collection. + +## List View - Members + +This Data Type is used by **Member Types** that is set to display as a Collection. + +## Media Picker + +The picker opens a modal to pick a specific media item from the Media tree. The value saved is the selected media node UDI. + +## Member Picker + +Displays a dropdown with all the available members. A single member can be selected. The value saved is the ID of the member. + +## Multi URL Picker + +This Data Type allows an editor to add an array of links. These can either be internal Umbraco pages external URLs or links to media in the Media section. The Data Type can be configured by limited number of links it is possible to add. + +## Multiple Image Media Picker + +The picker opens a modal to pick multiple images from the **Media** tree. The value saved is a comma separated string of media node UDIs. + +## Multiple Media Picker + +The picker opens a modal to pick multiple media items from the **Media** tree. The value saved is a comma separated string of media node UDIs. + +## Numeric + +A textbox to input a numeric value. + +## Radiobox + +This Data type enables editors to choose from a list of radiobuttons. + +## Richtext Editor + +A TipTap-based What You See Is What You Get (WYSIWYG) editor. This is the standard editor used to edit a larger amount of text. The editor has a lot of settings, which can be changed on the Richtext editor Data Type in the Settings section. + +Learn more about the configuration options in the [Rich Text Editor articles](../../backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/README.md). + +## Tags + +A textbox that allows you to use multiple tags on a **Document Type**. You can specify a Tag Group for the Data Type, if you need to use Tags on different sections of your site. + +## Textarea + +A textarea provides a multi-line plain-text editing control. You can set the maximum allowed characters for the textarea and the number of rows, if any. + +## Textstring + +A normal HTML input text field. + +## True/False + +A checkbox which saves either 0 or 1, depending on the checkbox being checked or not. A common use is to create a property with the 'umbracoNaviHide' alias and the Data Type True/False. This will provide editors with the option to hide nodes in the navigation menu on the website. + +## Upload + +Adds an upload field, which allows documents or images to be uploaded to Umbraco. This does not add them to the media library, they are added to the document data. + +There are five Upload Data Types: + +* Upload Article - Used for uploading and storing documents. +* Upload Audio - Used for uploading and storing digital audio files. +* Upload File - Used for uploading and storing different types of files in the Media section +* Upload Vector Graphics - Used for uploading and storing Scalable Vector Graphics (svg) files which are text files containing source code to draw the desired image. +* Upload Video - Used for uploading and storing video files. diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/Data-Types-Create.jpg b/17/umbraco-cms/fundamentals/data/data-types/images/Data-Types-Create.jpg new file mode 100644 index 00000000000..13eda36abaf Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/Data-Types-Create.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type-v10.png b/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type-v10.png new file mode 100644 index 00000000000..6223bf77e2f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type-v10.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type.png b/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type.png new file mode 100644 index 00000000000..5df8f2bca42 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/creating-a-data-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-8.png b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-8.png new file mode 100644 index 00000000000..87060cc586a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-8.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-9.png b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-9.png new file mode 100644 index 00000000000..f7341191ae5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types-9.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types.png b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types.png new file mode 100644 index 00000000000..fa5455cf48a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/default-data-types.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/dropdown-data-type-sample.png b/17/umbraco-cms/fundamentals/data/data-types/images/dropdown-data-type-sample.png new file mode 100644 index 00000000000..741b15b8d3b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/dropdown-data-type-sample.png differ diff --git a/17/umbraco-cms/fundamentals/data/data-types/images/viewing-data-type-reference.png b/17/umbraco-cms/fundamentals/data/data-types/images/viewing-data-type-reference.png new file mode 100644 index 00000000000..e911c377f9f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/data-types/images/viewing-data-type-reference.png differ diff --git a/17/umbraco-cms/fundamentals/data/defining-content/README.md b/17/umbraco-cms/fundamentals/data/defining-content/README.md new file mode 100644 index 00000000000..1349348ac35 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/defining-content/README.md @@ -0,0 +1,315 @@ +--- +description: Here you'll find an explanation of how content is defined in Umbraco +--- + +# Defining Content + +Before a piece of content can be created in the Umbraco backoffice, first it needs to be defined. That is why, when opening a blank installation of Umbraco, it is not possible to create content in the **Content** section. + +All content needs a blueprint that holds information about what kind of data can be stored on the content node or which editors are used. + +Additionally, it also needs information on how it is organized, where in the structure it is allowed, and so forth. This blueprint or definition is called a **Document Type**. + +## What is a Document Type? + +Document Types define what kind of content can be created in the **Content** section and what an end-user sees and can interact with. + +It can define entire pages or more limited content that can be reused on other nodes ie. a Search Engine Optimization (SEO) group. This means that you are in complete control of what type of content can be created and where. + +Another example is if there is a "`Blog post`" Document Type that has some properties containing a thumbnail, a name, and an author image. Then all blog posts using the "`Blog post`" Document Type, will allow the end user to fill in a thumbnail, author name, and an author image. + +A Document Type contains fieldsets (or groups) where you can apply rules about where the content can be created, allowed template(s), backoffice icons, etc. + +## 1. Creating a Document Type + +A Document Type is created using the Document Type editor in the **Settings** section. + +* Go to the **Settings** section in the backoffice. +* On the **Document Types** node click the menu icon (•••) to bring up the context menu. +* Here choose **Document Type with Template**. This will create a new Document Type with a template. The Template can be found under **Templates** in the **Settings** section which will be assigned as the default template for the Document Type. + +![CreateDoctype](../images/CreateDoctype.png) + +You can also choose to create a **Document Type** without a template and create **Folders** to organize your Document Types. Other options are to create Compositions and Element types, which you can read more about in the [Default Document Types](default-document-types.md) section. + +## 2. Defining the root node + +### Name the Document Type + +First, we're prompted to give the Document Type a **name**. This first Document Type will be the root node for our content, name it "`Home`". + +![Name the Document Type](../images/homePage.png) + +{% hint style="info" %} +The alias of the Document Type is automatically generated based on the property name. If you want to change the auto-generated alias, click the "**lock**" icon. The alias must be in camel case. For example: _`homePage`_. +{% endhint %} + +Having a root node lets you quickly query content as you know everything will be under the root node. + +### Adding Icons to the Document Type + +Choosing appropriate icons for your content nodes is a good way to give editors a better overview of the content tree. + +To set an icon for the Document Type click the document icon in the top left corner. This will open the icon select dialog. Search for "`Home"`and select the icon. This icon will be used in the content tree. + +![Home icon](../images/docTypeIcon.png) + +### Setting Permissions + +This will allow this Document Type to be created as the first content in the **Content** section. + +* Go to the **Structure** tab +* Tick the **Allow as root** toggle +* Save the Document Type by clicking **save** in the bottom right corner. + +![Allow as root](../images/docTypePermissions.png) + +## 3. Creating the content + +Now that we have the Document Type in place, we can create the content. + +* Go to the **Content section** +* Click on the menu icon next to **Content** +* Select the "`Home`" Document Type. We'll name it "`Home`" +* Then click the **Save and Publish** button. + +![Create homepage](../images/createHomepage.png) + +As we haven't created our properties, all we can see on the "`Home`" node is the Properties tab. This tab contains the default properties that are available on all content nodes in Umbraco. + +Let's add some properties of our own. + +## 4. Groups and properties + +In order to add the option to create different content on the same Document Type, some groups and properties need to be added. + +**Groups** + +Groups are a way to organize and structure the properties within the content, making it more manageable. It also makes it more user-friendly for content editors when creating or editing content on a website. + +A name can be added to the group and after properties can be added. + +**Properties** + +Each field on a Document Type is called a property. The property is given a **name**, an **alias** (used to output the properties contained in a template), and an **editor**. + +The editor determines what type of data the property will store and the input method. There is a wide range of default [property editors available](../../backoffice/property-editors/built-in-umbraco-property-editors/) and you can [customize additional editors](../../../customizing/property-editors/). + +Some editors require configuration where a configured editor is saved as a Data Type and can be reused for multiple properties and document types. These can be seen in the **Settings** section under **Data Types**. + +* Go to the **Settings section** +* Expand **Document Types** by clicking the arrow to the left +* Select the "`Home`" Document Type. + +{% hint style="info" %} +**Keyboard Shortcuts** + +Keyboard shortcuts are available when you are working with the Document Type editor. To see which shortcuts are available, click **ALT + SHIFT + K**. +{% endhint %} + +### Adding groups + +Before we start adding properties to the Document Type we need to create a group to hold the property. + +* Click **Add group** and name the group "`Content`". + +
Creating groups

Creating groups

+ +{% hint style="info" %} +_If you have multiple groups and/or properties you can order them with drag and drop or by entering a numeric sort order value. This is done by clicking **Reorder**._ +{% endhint %} + +To convert a group to a tab, see the [Convert a group to a tab](../adding-tabs.md#convert-a-group-to-a-tab) section in the [Using Tabs](../adding-tabs.md) article. + +### Adding properties + +Now that we have created a group we can start adding properties. Let's add a Rich Text editor to the Content group. + +* Click the **Add property** link in the **Content** group. This opens the property settings dialog. Here you can set the metadata for each property (name, alias, description) +* **Choose** which Data Type/property editor to use, and add validation if needed. +* Give the property a **name.** The name will be shown to the editor to make it relevant and understandable. Notice the alias is automatically generated based on the name. We'll name this "`Body Text`". + +![Adding a property](../images/addproperty.png) + +#### Property Editors + +* Clicking **Select Editor** will open the Select Editor dialog. Here, you can choose between all the available editors on the **Create a new Configuration** tab. This will create a new configuration or already configured editors in the **Available Configurations** tab. +* To make it easier to find what you need use the **search field** to filter by typing "`Rich`". Filtering will display configured properties first (under **Available configurations**) and all available editors under that. +* Select the **Rich Text editor** under **Create new**. This will let you configure the editor settings - the Rich Text editor for this property. + +![Choosing the Rich Text editor](../images/selectEditor.png) + +{% hint style="info" %} +The name of the Data Type is based on the name of the Document Type, the name of the property, and the property editor. Flor example: _Home - Body Text - Rich Text editor_. +{% endhint %} + +* Let's **rename** it to "`Basic Rich Text editor`" and only select the most necessary options. + * `bold` + * `italic` + * `alignLeft` + * `alignCenter` + * `link` + * `umbMediaPicker` +* When you are happy with the settings click **Submit**. + +{% hint style="info" %} +Selecting the **Mandatory** toggle makes the property mandatory and the content cannot be saved if no value is entered (in this case, the Richtext editor). + +You have the option to add additional validation by selecting a predefined validation method under the **Custom validation** dropdown (such as email, number, or URL). Or by selecting a custom validation and adding a regular expression. +{% endhint %} + +* **Save** the Document Type. +* If you go to the **Content section** and click on the `Home node` you will now see the `Content`group with the `Body Text` property. + +#### Property descriptions + +The description of the property is not necessary, but it´s a best practice as it guides the editor to use the property correctly. The property description supports some markdown and one custom collapse syntax: + +
+ +Bold + +You can make text in the description bold by wrapping it with `**` + +```md +This is **bold** +``` + +
+ +
+ +Italic + +You can make text in the description italic by wrapping it with `*` + +```md +This is *italic* +``` + +
+ +
+ +Links + +You can make links by using the syntax: + +```md +[This is an absolute link](https://google.com) +[This is a relative link](/umbraco#/media) +``` + +**Note**: Links will always have the`target="_blank"` set. This is currently not configurable. + +
+ +
+ +Images + +You can embed images by using this syntax: + +```md +![Image alt text](https://media.giphy.com/media/bezxCUK2D2TuBCJ7r5/giphy.gif) +``` + +
+ +
+ +Collapsible description + +You can make the description collapsible by using this syntax: + +```md +
+ This is displayed + This is hidden. +
+``` + +
+ +Now if we put it all together we get something like this: + +```md +This is **bold** +This is *italic* +[This is an absolute link](https://google.com) +[This is a relative link](/umbraco#/media) +-- +![Image alt text](https://media.giphy.com/media/bezxCUK2D2TuBCJ7r5/giphy.gif) +``` + +![Makrdown description example](../../../../../15/umbraco-cms/fundamentals/data/images/md-description.gif) + +## 5. Defining child nodes + +Next up we'll create a text page Document Type that will be used for subpages on the site. + +* Go back to the **Settings section** +* **Create** a new Document Type +* **Name** it "`Text Page`". +* Add a **group** called "`Content`" +* This time we'll add two properties: + * First, make a property called "`Summary`" using the **Textarea** editor + * Secondly, create a property called "`Body Text`" and reuse the **Rich Text Editor** Data Type. + +### Creating child nodes + +Before creating a Text Page in **Content** section, allow the Text Page Document Type to be created as a child node to the Home node. + +* **Select** the "`Home`" Document Type +* Go to the **Structure** group. +* Click **Add child** +* **Select** "`Text Page`". + +
Allow Child page

Allow Child page

+ +* Go to the **Content** section +* Click the menu icon (•••) next to the "`Home`" node +* **Select** the "`Text page`" Document Type. We'll name the page "`About us`". We now have a basic content structure. + +
+ +Document Types are flexible and can be used for defining pieces of reusable content or an entire page, to act as a container or repository. + +## 6. Exporting/Importing the Document Type + +You can also export document types from an already existing project/installation and import them into another project/installation. + +* Go to the **Settings** section +* Click **...** next to the **Document type** +* Select **Export**. When you click on the **Export** button, the Document Type is saved as a \*.udt file. + +![Exporting a Document Type](../images/v8Screenshots/export-document-type.png) + +To import a Document Type: + +* Go to the **Settings** section +* Click **...** next to the **Document type** +* Select **Import Document Type** +* Click on the **Import** button and browse to the Document Type you exported. The **Name** and **Alias** of the Document Type are displayed. +* Click **Import** to complete the process. + +![Importing a Document Type](../images/import-document-type.png) + +{% hint style="info" %} +1. If your Document Type contains compositions or inherits from another Document Type, then you need to export/import the Composition/Document Type too. +2. You cannot export/import document types on Umbraco Cloud. +{% endhint %} + +## More information + +* [Rendering Content](../../design/rendering-content.md) +* [Customizing Data Types](../data-types/) + +## Related Services + +* [ContentService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html) +* [ContentTypeService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentTypeService.html) + +## Tutorials + +* [Creating a basic website with Umbraco](../../../tutorials/creating-a-basic-website/) diff --git a/17/umbraco-cms/fundamentals/data/defining-content/default-document-types.md b/17/umbraco-cms/fundamentals/data/defining-content/default-document-types.md new file mode 100644 index 00000000000..57d079fb712 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/defining-content/default-document-types.md @@ -0,0 +1,41 @@ +--- +description: >- + On this page, you will find the default Document Types in Umbraco. If you want + to use these document types, you can create them in the Settings section. +--- + +# Default Document Types + +On this page, you will find the default Document Types in Umbraco. If you want to use these Document Types, you can create them in the Settings section. + +![Create Document Type](../images/CreateDoctype.png) + +## Document Type + +A Document Type defines the content structure and fields that can be used across different content items. When creating a Document Type without a template, you focus solely on structured content without tying it to a specific design or layout. This is ideal for content that doesn’t require direct front-end rendering, such as reusable blocks or items managed within a headless CMS setup. + +Use a Document Type without a template for structured, reusable content like metadata schemas, settings, or components such as product details and author profiles. + +## Document Type with Template + +A Document Type with a Template combines the content structure with a predefined visual presentation. This approach links your structured content with a specific page design, ensuring a consistent and cohesive look and feel across your site. It allows you to manage content and its appearance separately, which makes updates more efficient. + +Use a Document Type with a template for pages like blog posts, landing pages, or services that appear directly on the website. + +## Element Type + +An Element Type is a Document Type *without a template* designed for reusable and repeatable set of properties. These are primarily used in editors like the Block List Editor or Block Grid Editor to create structured, nested content. + +Element Types are not part of the Content tree and cannot render directly on the front end. When created, the **Is an Element Type** flag in the **Permissions** tab is automatically set to **True**. + +![Element type](../images/Element-Type.png)) + +Use an Element Type when defining building blocks for complex page layouts, such as grid blocks or call-to-action sections. They are an essential part of modular content design. + +## Folder + +The Folder in the Document Types section is used to organize and structure your Document Types within the Settings section. It serves purely as an organizational container, with no impact on the Content section or site functionality. + +Use a Folder to create logical groupings, like a folder named **Compositions** to hold all your Composition Document Types. This makes it easier to navigate and manage your Document Types, especially in larger projects. + +Folders are a powerful tool to keep your Document Types organized and your backoffice tidy. diff --git a/17/umbraco-cms/fundamentals/data/defining-content/document-type-localization.md b/17/umbraco-cms/fundamentals/data/defining-content/document-type-localization.md new file mode 100644 index 00000000000..317b0891eb2 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/defining-content/document-type-localization.md @@ -0,0 +1,103 @@ +--- +description: Here you will learn how to apply localization for Document Types in Umbraco. +--- + +# Document Type Localization + +{% hint style="warning" %} +This article is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +The Umbraco backoffice is localized to match the [user's configured language](../users/README.md). + +When defining a Document Type, you can apply localization to: + +* Document Type name and description. +* Property names and descriptions. +* Custom property validation messages. +* Tab and group names. + +Setting up localization for Document Types is a two-step process: + +* Create the localizations in [user defined backoffice localization file](../../../customizing/foundation/localization.md). +* Apply the localizations to the Document Type. + +{% hint style="info" %} +Everything in this article also applies to defining [Media Types](../creating-media/) and Member Types. +{% endhint %} + +## Creating localizations + +Once you have [registered a backoffice localization file](../../../customizing/extending-overview/extension-types/localization.md), you can add your localization texts for use in Document Types. The following localizations are used for the samples in this article: + +{% code title="doctype-en.js" lineNumbers="true" %} +```js +export default { + contentTypes: { + article: 'Article page', + 'article-desc': 'A textual, article-like page on the site. Use this as the main type of content.', + landing: 'Landing page', + 'landing-desc': 'An inviting, very graphical page. Use this as an entry point for a campaign, and supplement with Articles.' + }, + tabs: { + content: 'Page content', + seo: 'SEO configuration', + }, + groups: { + titles: 'Page titles' + }, + properties: { + title: 'Main title', + 'title-desc': 'This is the main title of the page.', + 'title-message': 'The main title is required for this page.', + subTitle: 'Sub title', + 'subTitle-desc': 'This is the sub title of the page.', + } +}; +``` +{% endcode %} + +{% hint style="info" %} +Umbraco must be restarted to register the localization manifest. Any subsequent localization text changes will need to be reloaded within the browser. +{% endhint %} + +## Applying localizations + +The localizations are applied by using the syntax `#{area alias}_{key alias}`. + +1. Create a **Document Type with template** called `#contentTypes_article` with **alias**: `articlePage`. +2. Under the newly created Document Type follow these steps: + +* Name the **description** to `#contentTypes_article-desc`. +* Create a new **tab** called `#tabs_content`. +* Add a new **group** called `#groups_titles`. +* Add a **property** called `#properties_title` with **alias** `title`. + * Set description to `{#properties_title-desc}`. + * Use a `TextString` editor. + * Enable to `Set this field as mandatory`. + * Under validation add `#properties_title-message`. + +{% hint style="info" %} +Property descriptions support [Umbraco Flavored Markdown](../../../reference/umbraco-flavored-markdown.md), which uses a different syntax (wrapped in brackets) to avoid conflicts with Markdown headers. +{% endhint %} + +![Applying localization to a property](../images/localization-document-type-editor-validation-v15.png) + +* Add a **property** called `#properties_subTitle` with **alias** `subTitle`. + * Set description to `{#properties_subTitle-desc}`. + * Use a `TextString` editor. +* Enable `Allow at root` in the **Structure** tab. + +![Applying localization to a Document Type](../images/localization-document-type-editor-v15.png) + +3. When creating and editing the content, you will see that the backoffice now uses the configured localizations. + +![Localized document creation dialog](../images/localization-document-editor-create.png) + +4. Create a new "Article" content: + +![Localized document editing](../images/localization-document-editor-v15.png) + +4. When trying to save the content without adding the mandatory content, you will see a warning as expected: + +![Localized property validation](../images/localization-document-editor-validation.png) diff --git a/17/umbraco-cms/fundamentals/data/dictionary-items.md b/17/umbraco-cms/fundamentals/data/dictionary-items.md new file mode 100644 index 00000000000..a0098c749eb --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/dictionary-items.md @@ -0,0 +1,116 @@ +--- +description: Creating Dictionary Items in Umbraco +--- + +# Dictionary Items + +Depending on how your site is set up, not all content is edited through the **Content** section. There might be some text in your templates that needs translation. Using Dictionary Items, you can store a value for each language. Dictionary Items have a unique key that is used to fetch the value of the Dictionary Item. + +Dictionary Items can be managed from the **Translation** section. Let's take a look at an example. In this example, we will translate "Welcome to Umbraco" from within the template and add it to the dictionary: + +
+ +## Adding a Dictionary Item + +To add a Dictionary Item: + +1. Go to the **Translation** section. +2. Click on **Dictionary** in the **Translation** tree and select **Create**. +3. Enter the **Name** for the dictionary item. Let's say _Welcome_. +4. Enter the values for the different language versions. + +
+5. Click **Save**. + +### Grouping Dictionary Items + +To group dictionary items: + +1. Go to the **Translation** section. +2. Click on **Dictionary** in the **Translation** tree and select **Create**. +3. Enter the **Name** for the dictionary item. Let's say _Contact_. +4. Click **Create**. +5. Click on **Contact** and select **Create**. +6. Enter the **Name** of the item to be created under the **Contact** group. +7. Click **Create**. +8. Enter the values for the different language versions. + +
+9. Click **Save**. + +## Editing Dictionary Items + +To edit a dictionary item, follow these steps: + +1. Go to the **Translation** section. +2. Use the **Dictionary** tree to locate the item you need to update/edit. + * Alternatively, you can use the _search field_ in the top-right corner. +3. Make the edits you need to make. +4. Click **Save** to save the changes. + +{% hint style="info" %} +It will only be possible to edit the language(s) that the given user has access to. The value of the remaining languages will be _read-only_. + +Which language a user has access to is determined by the "Language permissions" set on the User Group. Learn more about this feature in the [Users](users/README.md#creating-a-user-group) article. +{% endhint %} + +## Fetching Dictionary Values in the Template + +To fetch dictionary values in the template, replace the text with the following snippet: + +```csharp +@Umbraco.GetDictionaryValue("Welcome") +``` + +![Rendering dictionary item](images/rendering-dictionary-item.png) + +Alternatively, you can specify an `altText` which will be returned if the dictionary value is empty. + +```csharp +@Umbraco.GetDictionaryValueOrDefault("Welcome", "Another amazing day in Umbraco") +``` + +![Rendering dictionary item](images/rendering-altvalue-dictionary-item.png) + +## Importing and exporting Dictionary Items + +In some cases, you might want to use the same Dictionary Items on multiple Umbraco websites. For this, you can use the export and import functionality to quickly copy the items from one website to another. + +### Exporting Dictionary Items + +1. Go to the **Translation** section in the Umbraco backoffice. +2. Locate the Dictionary Item (or group) you want to copy in the section tree. +3. Click **...** next to the Dictionary item (or group). +4. Select **Export...**. +5. Decide whether you want to also include descendants. +6. Click **Export**. + +This will download a `.udt` file which you can use to import the Dictionary items on another Umbraco website. + +![Options menu with the Export feature](images/export.png) + +### Importing Dictionary Items + +1. Go to the **Translation** section in the Umbraco backoffice. +2. Click **...** next to the **Dictionary** tree. +3. Select **Import...**. +4. Click on **Import**. +5. Find and select the `.udt` file containing the Dictionary Items. +6. Click **Open** in the file browser. +7. Review the Dictionary Items for import. +8. Choose where to import the items. +9. Click on **Import**. + +The Dictionary Items have now been added to your website. + +![Review the Dictionary Items for import before confirming](images/import.png) + +## Using Dictionary Item in a Multilingual website + +To use Dictionary Items in a multilingual website, see the [Creating a Multilingual Site](../../tutorials/multilanguage-setup.md) article. + +## Related Links + +* [API reference for the DictionaryItem](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Models.DictionaryItem.html) +* [Localization Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ILocalizationService.html) +* [Creating a Multilingual Site](../../tutorials/multilanguage-setup.md) diff --git a/17/umbraco-cms/fundamentals/data/images/Add-tab.png b/17/umbraco-cms/fundamentals/data/images/Add-tab.png new file mode 100644 index 00000000000..778cf1f3ea1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Add-tab.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Add-tab.png.png b/17/umbraco-cms/fundamentals/data/images/Add-tab.png.png new file mode 100644 index 00000000000..73e5077434e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Add-tab.png.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Composition-add-tab.gif b/17/umbraco-cms/fundamentals/data/images/Composition-add-tab.gif new file mode 100644 index 00000000000..e37c0a3fee9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Composition-add-tab.gif differ diff --git a/17/umbraco-cms/fundamentals/data/images/Composition-hide-unavailable-options.PNG b/17/umbraco-cms/fundamentals/data/images/Composition-hide-unavailable-options.PNG new file mode 100644 index 00000000000..a1e0cb68f00 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Composition-hide-unavailable-options.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/Create-dictionary-item.png b/17/umbraco-cms/fundamentals/data/images/Create-dictionary-item.png new file mode 100644 index 00000000000..487c8cce9d3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Create-dictionary-item.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/CreateDoctype.png b/17/umbraco-cms/fundamentals/data/images/CreateDoctype.png new file mode 100644 index 00000000000..2ff143255d4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/CreateDoctype.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Doc-Type-Composition-Create.png b/17/umbraco-cms/fundamentals/data/images/Doc-Type-Composition-Create.png new file mode 100644 index 00000000000..01a033a8322 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Doc-Type-Composition-Create.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.jpg new file mode 100644 index 00000000000..16877952fce Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.png new file mode 100644 index 00000000000..e0dd28eea5d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Adding-Properties.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.jpg new file mode 100644 index 00000000000..05eab4013e4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.png new file mode 100644 index 00000000000..681f8abb02d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-At-Root.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.jpg new file mode 100644 index 00000000000..379bd460cbf Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.png new file mode 100644 index 00000000000..5cf0eab4019 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Allow-Child-Node.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.jpg new file mode 100644 index 00000000000..d4228f79d86 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.png new file mode 100644 index 00000000000..1cd102415c7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Child-Node-Created.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.jpg new file mode 100644 index 00000000000..cbd80fd877c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.png new file mode 100644 index 00000000000..78a3a88a926 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Choosing-Icon.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.jpg new file mode 100644 index 00000000000..5eeab314605 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.png new file mode 100644 index 00000000000..189c215b561 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create-Tab.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.jpg new file mode 100644 index 00000000000..8ca1e52161d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.png new file mode 100644 index 00000000000..bf04c748479 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Create.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Keyboard-Shortcuts.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Keyboard-Shortcuts.jpg new file mode 100644 index 00000000000..f02269a61d7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Keyboard-Shortcuts.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Name.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Name.jpg new file mode 100644 index 00000000000..3c97dcee728 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Name.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Rich-Text-Property.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Rich-Text-Property.jpg new file mode 100644 index 00000000000..a7df64bc69f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Rich-Text-Property.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.jpg b/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.jpg new file mode 100644 index 00000000000..0132dcbf489 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.png b/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.png new file mode 100644 index 00000000000..1ce4b43996c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Document-Type-Root-Node-Created.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Element-Type.png b/17/umbraco-cms/fundamentals/data/images/Element-Type.png new file mode 100644 index 00000000000..e568ea61e17 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Element-Type.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Generic-tab.png b/17/umbraco-cms/fundamentals/data/images/Generic-tab.png new file mode 100644 index 00000000000..8f0056f27c5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Generic-tab.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-Groups-Assign.jpg b/17/umbraco-cms/fundamentals/data/images/Member-Groups-Assign.jpg new file mode 100644 index 00000000000..7b8256d2b9c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-Groups-Assign.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-Groups-Create.jpg b/17/umbraco-cms/fundamentals/data/images/Member-Groups-Create.jpg new file mode 100644 index 00000000000..46ae9ab3f19 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-Groups-Create.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor.png b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor.png new file mode 100644 index 00000000000..720997b7c7b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new.png b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new.png new file mode 100644 index 00000000000..023273e0715 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new1.PNG b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new1.PNG new file mode 100644 index 00000000000..a255cb732fc Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-Type-Editor_new1.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-group.png b/17/umbraco-cms/fundamentals/data/images/Member-group.png new file mode 100644 index 00000000000..4605e90f13f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-group.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Member-group1.PNG b/17/umbraco-cms/fundamentals/data/images/Member-group1.PNG new file mode 100644 index 00000000000..f52e963f14a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Member-group1.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/Members-Generic-Properties.jpg b/17/umbraco-cms/fundamentals/data/images/Members-Generic-Properties.jpg new file mode 100644 index 00000000000..df6a94a37ac Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Members-Generic-Properties.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Members-Info.jpg b/17/umbraco-cms/fundamentals/data/images/Members-Info.jpg new file mode 100644 index 00000000000..e1ca5323694 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Members-Info.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Members-Tabs.jpg b/17/umbraco-cms/fundamentals/data/images/Members-Tabs.jpg new file mode 100644 index 00000000000..f9d254a230d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Members-Tabs.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Publish-Timezone-Difference.jpg b/17/umbraco-cms/fundamentals/data/images/Publish-Timezone-Difference.jpg new file mode 100644 index 00000000000..49bac0b0d90 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Publish-Timezone-Difference.jpg differ diff --git a/17/umbraco-cms/fundamentals/data/images/Relations-in-the-backoffice.png b/17/umbraco-cms/fundamentals/data/images/Relations-in-the-backoffice.png new file mode 100644 index 00000000000..2a55e85f9b0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Relations-in-the-backoffice.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/Reorder-tabs.gif b/17/umbraco-cms/fundamentals/data/images/Reorder-tabs.gif new file mode 100644 index 00000000000..f72d6585209 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Reorder-tabs.gif differ diff --git a/17/umbraco-cms/fundamentals/data/images/Scheduled-publishing.PNG b/17/umbraco-cms/fundamentals/data/images/Scheduled-publishing.PNG new file mode 100644 index 00000000000..2d459b614d5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/Scheduled-publishing.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/User-Permissions.png b/17/umbraco-cms/fundamentals/data/images/User-Permissions.png new file mode 100644 index 00000000000..80b66e7080c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/User-Permissions.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/User-Type-Info.png b/17/umbraco-cms/fundamentals/data/images/User-Type-Info.png new file mode 100644 index 00000000000..44f415daa9a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/User-Type-Info.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/addproperty.png b/17/umbraco-cms/fundamentals/data/images/addproperty.png new file mode 100644 index 00000000000..0fa9fd96537 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/addproperty.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/api-user.png b/17/umbraco-cms/fundamentals/data/images/api-user.png new file mode 100644 index 00000000000..7f4be5d1379 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/api-user.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/assign-member-group.png b/17/umbraco-cms/fundamentals/data/images/assign-member-group.png new file mode 100644 index 00000000000..81ee0a8f6c3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/assign-member-group.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/assign-member-group1.PNG b/17/umbraco-cms/fundamentals/data/images/assign-member-group1.PNG new file mode 100644 index 00000000000..f7341617c77 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/assign-member-group1.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/composition.png b/17/umbraco-cms/fundamentals/data/images/composition.png new file mode 100644 index 00000000000..9f82add0c8a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/composition.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/create-relation-type.png b/17/umbraco-cms/fundamentals/data/images/create-relation-type.png new file mode 100644 index 00000000000..c41346ce89c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/create-relation-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/create-user-group.png b/17/umbraco-cms/fundamentals/data/images/create-user-group.png new file mode 100644 index 00000000000..67e2004a8b6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/create-user-group.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/createGroup_new.png b/17/umbraco-cms/fundamentals/data/images/createGroup_new.png new file mode 100644 index 00000000000..25b40cc09d7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/createGroup_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/createHomepage.png b/17/umbraco-cms/fundamentals/data/images/createHomepage.png new file mode 100644 index 00000000000..d02e29e9be1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/createHomepage.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/default-permissions-v16.png b/17/umbraco-cms/fundamentals/data/images/default-permissions-v16.png new file mode 100644 index 00000000000..f16114eafb8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/default-permissions-v16.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/default-permissions.png b/17/umbraco-cms/fundamentals/data/images/default-permissions.png new file mode 100644 index 00000000000..4caefbc30b9 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/default-permissions.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/default-relation-types.png b/17/umbraco-cms/fundamentals/data/images/default-relation-types.png new file mode 100644 index 00000000000..d8e4fc4628f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/default-relation-types.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/dictionary-item-values.png b/17/umbraco-cms/fundamentals/data/images/dictionary-item-values.png new file mode 100644 index 00000000000..bea50d97f4e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/dictionary-item-values.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/dictionary-item.png b/17/umbraco-cms/fundamentals/data/images/dictionary-item.png new file mode 100644 index 00000000000..b69dbefae0e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/dictionary-item.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/display-dictionary-item.png b/17/umbraco-cms/fundamentals/data/images/display-dictionary-item.png new file mode 100644 index 00000000000..d9e5f2f259f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/display-dictionary-item.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/docTypeIcon.png b/17/umbraco-cms/fundamentals/data/images/docTypeIcon.png new file mode 100644 index 00000000000..9383f25f90e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/docTypeIcon.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/docTypePermissions.png b/17/umbraco-cms/fundamentals/data/images/docTypePermissions.png new file mode 100644 index 00000000000..03fcaca6107 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/docTypePermissions.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/export.png b/17/umbraco-cms/fundamentals/data/images/export.png new file mode 100644 index 00000000000..c9c209d1ce5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/export.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/granular-permissions.png b/17/umbraco-cms/fundamentals/data/images/granular-permissions.png new file mode 100644 index 00000000000..cc1455ca16d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/granular-permissions.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/homePage.png b/17/umbraco-cms/fundamentals/data/images/homePage.png new file mode 100644 index 00000000000..7c3e05f31d5 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/homePage.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/import-document-type.png b/17/umbraco-cms/fundamentals/data/images/import-document-type.png new file mode 100644 index 00000000000..3450fc8287d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/import-document-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/import.png b/17/umbraco-cms/fundamentals/data/images/import.png new file mode 100644 index 00000000000..97c5508a8f8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/import.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-editor-create.png b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-create.png new file mode 100644 index 00000000000..58b02eb6b1c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-create.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-editor-v15.png b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-v15.png new file mode 100644 index 00000000000..47ed19ed881 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-v15.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-editor-validation.png b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-validation.png new file mode 100644 index 00000000000..a81ce080608 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-editor-validation.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-editor.png b/17/umbraco-cms/fundamentals/data/images/localization-document-editor.png new file mode 100644 index 00000000000..c47f8f8bc71 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-editor.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-v15.png b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-v15.png new file mode 100644 index 00000000000..9f3533c9eab Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-v15.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation-v15.png b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation-v15.png new file mode 100644 index 00000000000..c14a6bb5ca3 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation-v15.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation.png b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation.png new file mode 100644 index 00000000000..4ce31a3eea8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor-validation.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor.png b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor.png new file mode 100644 index 00000000000..2b70a040459 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/localization-document-type-editor.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/md-description.gif b/17/umbraco-cms/fundamentals/data/images/md-description.gif new file mode 100644 index 00000000000..0c5f23159df Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/md-description.gif differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-images.png b/17/umbraco-cms/fundamentals/data/images/member-images.png new file mode 100644 index 00000000000..0ebfc085e8e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-images.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-type-composition-setting.PNG b/17/umbraco-cms/fundamentals/data/images/member-type-composition-setting.PNG new file mode 100644 index 00000000000..c5f7e34b07d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-type-composition-setting.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-type-composition.PNG b/17/umbraco-cms/fundamentals/data/images/member-type-composition.PNG new file mode 100644 index 00000000000..ed681f1bc84 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-type-composition.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-type-property-settings.png b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings.png new file mode 100644 index 00000000000..13c489b587d Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new.png b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new.png new file mode 100644 index 00000000000..7be01dded3e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new1.PNG b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new1.PNG new file mode 100644 index 00000000000..268d377ea3c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/member-type-property-settings_new1.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/parent-siblings-children.png b/17/umbraco-cms/fundamentals/data/images/parent-siblings-children.png new file mode 100644 index 00000000000..1ace04fdb61 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/parent-siblings-children.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/per-doctype-override.png b/17/umbraco-cms/fundamentals/data/images/per-doctype-override.png new file mode 100644 index 00000000000..33d9c68ad6b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/per-doctype-override.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-1.png b/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-1.png new file mode 100644 index 00000000000..e50e559391b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-1.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-2.png b/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-2.png new file mode 100644 index 00000000000..55051c7c9ac Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/prevent-cleanup-part-2.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/relation-alias.png b/17/umbraco-cms/fundamentals/data/images/relation-alias.png new file mode 100644 index 00000000000..adb3724f63e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/relation-alias.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/relation-types-tree.png b/17/umbraco-cms/fundamentals/data/images/relation-types-tree.png new file mode 100644 index 00000000000..99f780d3cb6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/relation-types-tree.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/rendering-altvalue-dictionary-item.png b/17/umbraco-cms/fundamentals/data/images/rendering-altvalue-dictionary-item.png new file mode 100644 index 00000000000..e43fc16234c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/rendering-altvalue-dictionary-item.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/rendering-dictionary-item.png b/17/umbraco-cms/fundamentals/data/images/rendering-dictionary-item.png new file mode 100644 index 00000000000..0e03646e5a2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/rendering-dictionary-item.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/schedule.png b/17/umbraco-cms/fundamentals/data/images/schedule.png new file mode 100644 index 00000000000..0ecf9270a25 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/schedule.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/scheduled-publishing-8.png b/17/umbraco-cms/fundamentals/data/images/scheduled-publishing-8.png new file mode 100644 index 00000000000..d27a20c238f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/scheduled-publishing-8.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/selectEditor.png b/17/umbraco-cms/fundamentals/data/images/selectEditor.png new file mode 100644 index 00000000000..92e375529fc Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/selectEditor.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/user-groups-menu-v16.png b/17/umbraco-cms/fundamentals/data/images/user-groups-menu-v16.png new file mode 100644 index 00000000000..9fff1b7f592 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/user-groups-menu-v16.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/user-groups-v16.png b/17/umbraco-cms/fundamentals/data/images/user-groups-v16.png new file mode 100644 index 00000000000..9eaef60cbe2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/user-groups-v16.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/user-groups.png b/17/umbraco-cms/fundamentals/data/images/user-groups.png new file mode 100644 index 00000000000..0bee87e6a5e Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/user-groups.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty.PNG new file mode 100644 index 00000000000..e1bea9ab123 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty_new.png b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty_new.png new file mode 100644 index 00000000000..90b6811430f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/addproperty_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/compositions.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/compositions.PNG new file mode 100644 index 00000000000..f7659939395 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/compositions.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createAboutUs.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createAboutUs.PNG new file mode 100644 index 00000000000..1a3dcaa872b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createAboutUs.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createDoctype.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createDoctype.PNG new file mode 100644 index 00000000000..38a1fc35656 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createDoctype.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup.PNG new file mode 100644 index 00000000000..0296832fb4c Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup_new.png b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup_new.png new file mode 100644 index 00000000000..d472b03643a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createGroup_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createHomepage.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createHomepage.PNG new file mode 100644 index 00000000000..f81f9f46f2b Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/createHomepage.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypeIcon.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypeIcon.PNG new file mode 100644 index 00000000000..8e69be56ee0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypeIcon.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypePermissions.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypePermissions.PNG new file mode 100644 index 00000000000..f7db0099d66 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/docTypePermissions.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/export-document-type.png b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/export-document-type.png new file mode 100644 index 00000000000..6aab567e14f Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/export-document-type.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/homePage.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/homePage.PNG new file mode 100644 index 00000000000..09f09c4a42a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/homePage.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor.PNG new file mode 100644 index 00000000000..8243f86002a Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor_new.png b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor_new.png new file mode 100644 index 00000000000..e9535792256 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/selectEditor_new.png differ diff --git a/17/umbraco-cms/fundamentals/data/images/v8Screenshots/setPagePermissions.PNG b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/setPagePermissions.PNG new file mode 100644 index 00000000000..6468e326822 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/v8Screenshots/setPagePermissions.PNG differ diff --git a/17/umbraco-cms/fundamentals/data/images/view-relations.png b/17/umbraco-cms/fundamentals/data/images/view-relations.png new file mode 100644 index 00000000000..5dcd9ce63a0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/data/images/view-relations.png differ diff --git a/17/umbraco-cms/fundamentals/data/members.md b/17/umbraco-cms/fundamentals/data/members.md new file mode 100644 index 00000000000..be68820eda1 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/members.md @@ -0,0 +1,119 @@ +--- +description: >- + Members are used for registering and authentication external / frontend users + of an Umbraco installation. This could be Forum members and Intranet members. +--- + +# Members + +Members are used for registering and authenticating external users of an Umbraco installation (ie. forum members, intranet users and so forth). + +This guide will explain how to define and create members in the backoffice. If you want to work with members using the service APIs, links can be found at the end of the document. + +There is a default Member Type that can be used to create members. You can customize this to fit your needs or create your own Member Type from scratch. + +## Creating a Member + +Go to the **Members** section and click **Create**. + +Members have a number of mandatory properties that need to be filled in before a member can be saved. Some of the properties are **Username**, **Email**, two **Password fields** and so on. + +There are also a number of default properties which are stored in the database in the tables `Member` and`TwoFactorLogin`: + +* `umbracoMemberFailedPasswordAttempts` +* `umbracoMemberApproved` +* `umbracoMemberLockedOut` +* `umbracoTwoFactorLogin` +* `umbracoMemberLastLockoutDate` +* `umbracoMemberLastLogin` +* `umbracoMemberLastPasswordChangeDate` + +Once the Member is created and saved you can access it by expanding the Members tree and clicking **All Members** to get a collection. You can also view members of a specific type by selecting the member type in the Members tree. + +## [Sensitive data](../../reference/security/sensitive-data-on-members.md) + +Sensitive properties on a members data will not be displayed to backoffice users unless they have appropriate permissions. In order to see the values of the default properties in the **Member** tab you need to have the Sensitive data User Group. By having this group added to a user they will also have the option to mark member type properties as sensitive. + +More information can be found under [security](../../reference/security/sensitive-data-on-members.md). + +## Creating a Member Type + +You can create your own Member Types and add tabs, groups and properties as you would with Document Types. + +Go to the **Settings** section, click **...** next to **Member Types** and select **Create**. You will now be taken to the Member Type editor that is used to define and edit the Member Type. Name the new Member Type and click **Save**. + +![Member Type Editor](images/member-type-composition.PNG) + +Once created, the Member Type will have no properties, so you have the freedom to add your own properties or compositions. + +### Assigning a Member Composition + +When creating a Member Type you can assign compositions. Compositions allow you to inherit tabs and properties from existing member types instead of creating them from scratch. + +For example on the member type that you have created, click on **Composition**. Then you can choose the existing **Member** type which then you will inherit its tabs, groups, and properties. + +

Composition Member Type

+ +The default **Member** type has a **Membership** group which includes `umbracoMemberComments` property along with the other default properties. The other properties can be seen only in the **Member** tab when creating a member. + +It is possible to add more groups and more properties to each of the Member Types you create, as well as the default Member Type. + +## Creating Member Groups + +Member Groups define roles for your members that can be used for role-based protection. A member can be in multiple groups. + +![Creating a Member Group](images/Member-group1.PNG) + +To create a new Member Group click the menu icon next to the **Member Groups** node in the Members section. Choose **Create**, name the group, and save the group. + +### Assigning a Member Group + +To assign a member to a specific group find the member you wish to assign and find the **Properties** group. Here you can see which groups the member is already part of. You can also add the member to more groups or remove the member from already assigned groups: + +![Assigning a Member Group](images/assign-member-group1.PNG) + +## Technical + +As a developer you are able to leverage your website when you build on the Members section of Umbraco. The member's section is by default in the Umbraco backoffice, but you can still use it to implement some work on your front end. Members are created using ASP.NET Core Identity, so there are some provider settings that can be set in appsettings.json - here are the defaults: + +```json +{ + "$schema": "appsettings-schema.json", + "Umbraco": { + "CMS": { + "Security": { + "AllowPasswordReset": true, + "AuthCookieDomain": "(No default, but takes a string)", + "AuthCookieName": "UMB_UCONTEXT", + "KeepUserLoggedIn": false, + "UsernameIsEmail": true, + "HideDisabledUsersInBackoffice": false, + "AllowedUserNameCharacters": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+\\", + "MemberPassword": { + "RequiredLength": 10, + "RequireNonLetterOrDigit": false, + "RequireDigit": false, + "RequireLowercase": false, + "RequireUppercase": false, + "MaxFailedAccessAttemptsBeforeLockout": 5, + "HashAlgorithmType": "HMACSHA256" + } + } + } + } +} +``` + +You can find out more about the services methods in the reference section of the documentation by following the links below. + +## References + +* Video: [Adding a member](https://www.youtube.com/watch?v=gdvfrqQcAGY) +* Video: [Member Type Properties](https://www.youtube.com/watch?v=E_es3x_H5oU) +* Video: [Role-Based Protection](https://www.youtube.com/watch?v=wVR9OBnaNZQ) + +### Related Services + +* [MemberService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.MemberService.html) +* [MemberType Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.MemberTypeService.html) +* [MemberGroup Service](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.IMemberGroupService.html) diff --git a/17/umbraco-cms/fundamentals/data/relations.md b/17/umbraco-cms/fundamentals/data/relations.md new file mode 100644 index 00000000000..1c09107870e --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/relations.md @@ -0,0 +1,67 @@ +--- +description: Learn about relations and how to create and manage them. +--- + +# Relations + +Umbraco sections are built around the concept of 'trees' and there is an implicit relationship between items in a section tree. + +![Parent, Siblings & Children](../../../../10/umbraco-cms/fundamentals/data/images/parent-siblings-children.png) + +We refer to these relationships in the manner of a 'Family Tree'. One content item might be the 'Parent' of some content items, and those items would be referred to as the 'Children' of that parent. Items within the same branch of the tree can also be described as 'Ancestors' or 'Descendants' of an item. + +There are methods available to support querying content items by their relative position to the current page. This is possible using the following concepts: `Model.Ancestors()`, `Model.Children()`, or `Model.Descendants()`. + +In some cases there are no direct relationships between two items in a tree, but they are still somehow 'related'. This could be the alternate language translation pages of a content page. + +In other cases there is a 'relation' between different types of entities. This could be a relation between Content and Member, or Member and MediaFolder. You might need to be able to retrieve and display the uploaded images from a specific logged-in Member. + +These are the scenarios where the concept of **Umbraco Relations** provides a solution. + +## The Concept of Umbraco Relations + +Umbraco Relations allow you to relate almost any object in Umbraco to almost any other Umbraco object. This is done by defining a new _Relation Type_. + +### How is this different to pickers? + +With a Content, Member, or Media picker the relationship only works as a 1-way street. The content item knows it has 'picked' another content item but that other content item does not know where it has been picked. + +Umbraco Relations works as a 2-way street. When creating a relation between two different types of entities, it will be possible to find one entity from the other and vice versa. As an example this provides the option to list out all the pages that a content banner had been picked on. + +## Relation Types + +A Relation Type specifies how two types of entities are related. Two items might be related under multiple Relation Types, and you might only be interested in your 'Related Language Page' Relation Type. + +## Viewing Relations + +It is possible to view the existing Relation Types from the Umbraco backoffice: + +1. Access the Umbraco Backoffice. +2. Navigate to the **Settings** section. +3. Locate the **Advanced** group in the sidebar. +4. Select **Relations**. + +![View Relations](images/Relations-in-the-backoffice.png) + +On the dashboard all defined relations will be listed. Select a Relation to view a list of all the objects that have been related for that specific Relation Type. + +## Creating Relations + +You can create Relations using the RelationService API via code. + +[Some examples are provided here in the RelationService Documentation Page](../../reference/management/using-services/relationservice.md) + +## Use cases + +You might want to create a 'Relation' between two objects either as: + +* A response to a backoffice event. For example, a content item being published that has picked other content items. Storing a relationship between these items would make querying between them easier. Perhaps show all the pages on which a particular 'banner' has been picked. +* A logged-in member on the front end of an Umbraco website might have the facility to upload images. In response, the implementation could store the photos programmatically in the Media Section and at the same time, create a Relation to record the relationship between the member and their uploaded pictures. On an image gallery page, it would be possible to display all the gallery images for the current logged-in Member using the relations. + +## Community Packages + +Some of the community packages that use Relations are listed below: + +* ['Relations Picker'](https://our.umbraco.com/packages/backoffice-extensions/relations-picker/) - a content picker that automatically creates Relations. +* ['ContentRelations'](https://our.umbraco.com/packages/backoffice-extensions/contentrelations/) - allows you to relate two items via the Backoffice. +* ['LinkedPages'](https://our.umbraco.com/packages/backoffice-extensions/linked-pages/) - Provides a LinkedPages context item to show, edit, and add relations between content pages. diff --git a/17/umbraco-cms/fundamentals/data/scheduled-publishing.md b/17/umbraco-cms/fundamentals/data/scheduled-publishing.md new file mode 100644 index 00000000000..485aaf1e881 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/scheduled-publishing.md @@ -0,0 +1,62 @@ +--- +description: >- + Each document in Umbraco can be scheduled for publishing and unpublishing on a + pre-defined date and time. +--- + +# Scheduled Publishing + +Each document in Umbraco can be scheduled for publishing and unpublishing on a pre-defined date and time. + +You can find the options to do this click on the arrow next to the **Save and publish** button and pick **Schedule...** + + + +
Scheduled publishing

Scheduled publishing

+ +This will open a **Schedule Publishing** dialog where you can specify dates and time. + +![Scheduled publishing](images/scheduled-publishing.png) + +## Timezones + +Your server may be in a different timezone than where you are located. You are able to select a date and time in your timezone and Umbraco will make sure that the item gets published at that time. So, if you select 12 PM then the item will be published at 12PM in the timezone you are in. This may be 8 PM on the server, which is indicated when you select the date and time. + +
Scheduled publishing time

Scheduled publishing

+ +If you are in the same timezone as the server, this message will not appear under the date picker. + +{% hint style="info" %} +In Umbraco versions lower than 7.5, the time you select has to be the time on the server. These older versions of Umbraco do not detect your local time zone. +{% endhint %} + +## Permissions + +All users with access to the Content section in the Umbraco backoffice are able to schedule content for publishing/unpublish. + +## Configuration + +In some cases you will need to adjust your configuration to ensure that scheduled publishing/unpublishing works. The schedule works by the server sending an HTTP(S) request to itself. + +If you are in a load balanced environment special care must be given to ensure you've configured this correctly, [see the docs here](../setup/server-setup/load-balancing/file-system-replication.md) + +If you are not load balancing, the way that Umbraco determines the base URL to send the scheduled HTTP(S) request to is as follows: + +* umbracoSettings:settings/web.routing/@umbracoApplicationUrl if it exists _(see_ [_these docs_](../../reference/configuration/webroutingsettings.md) _for details)_ +* Else umbracoSettings:settings/scheduledTasks/@baseUrl if it exits _(deprecated)_ +* Else umbracoSettings:distributedCall/servers if we have the server in there _(deprecated, see load balance docs)_ +* Else it's based on the first request that the website receives and uses the base URL of this request _(default)_ + +If the `umbracoApplicationUrl` is used, the value also specifies the scheme (either HTTP or HTTPS). The request for scheduled publishing will always be sent over HTTPS if the appSettings `umbracoUseSSL` is set to `true`. + +## Troubleshooting + +If your scheduled publishing/unpublishing is not working as expected it is probably an issue that your server cannot communicate with the scheduled publishing endpoint. This can be caused by a number of reasons such as: + +* Url rewrites in place that prevent the endpoint from being reached +* DNS misconfiguration not allowing the server to communicate to the base URL used in the first request that the website receives - which could be directly affected by a firewall/Network Address Translation (NAT)/load balancer that your server sites behind +* Secure Sockets Layer (SSL) and/or umbracoUseSSL misconfiguration not allowing the server to communicate to the scheduled publishing endpoint on the correct http/https scheme + +To better diagnose the issue you can temporarily change your log4net config settings to be `DEBUG` instead of `INFO`. This will give you all sorts of information including being able to see whether or not the scheduled publishing endpoint is being reached or not. + +In some cases it might be easiest to specify the [umbracoSettings:settings/web.routing/@umbracoApplicationUrl](../../reference/configuration/webroutingsettings.md) setting. This is to ensure that your server is communicating to itself on the correct URL. diff --git a/17/umbraco-cms/fundamentals/data/users/README.md b/17/umbraco-cms/fundamentals/data/users/README.md new file mode 100644 index 00000000000..4ffaf2204d4 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/users/README.md @@ -0,0 +1,131 @@ +--- +description: >- + Learn how to create, manage, and assign permissions to users in the Umbraco backoffice. +--- + +# Users + +Users are people who have access to the Umbraco backoffice (not to be confused with [Members](../members.md)). These could include Content Editors, Translators, Web Designers, and Developers. + +This guide will walk you through how to create and invite users, manage user profiles, work with User Groups and permissions in the backoffice. + +## Creating a User + +To create or invite a User: + +1. Go to the **Users** section in the backoffice. +2. Select **Create -> User**. Alternatively, click **Invite...**. +3. Enter the **Name** and **Email** of the new user. +4. Select which **User group** the new user should be added to. +5. *[Optional]* Enter a **Message** for the invitation. +6. Click **Create user** or **Send invite**. + +Once you have created the user, the new user will receive a system-generated password for their initial login. This password needs to be used to access the account. + +### Managing a User Profile + +Open a user’s profile from the **Users** section to update: + +* Profile photo. +* Email address of the user. +* UI Culture (sets the backoffice language of the user account). +* User Group (determines the scope of access in the backoffice). +* Start nodes for both Content and Media sections to limit access. + +## Managing Users + +When working with multiple users in Umbraco, the user screen provides tools to help you quickly locate and manage users using filters and layout options. + +### Filter and Organize Users + +At the top of the Users section, use the search bar to quickly find a user by typing their name or email address. + +Use the **Status** filter to narrow down users based on their current state: + +* Active – Users who have logged in and are enabled. +* Disabled – Users whose access has been explicitly turned off. +* Locked out - User has been automatically blocked from logging in after too many failed login attempts. +* Invited - User has been invited to access the Umbraco backoffice. +* Inactive – Users who haven't logged in or have been disabled. + +The **Groups** filter lets you view users based on the user groups they belong to. For example, Administrators, Editors, Sensitive data, Translators, and Writers. + +Use **Order by** to sort users by: + +* Name (A–Z) +* Name (Z-A) +* Newest +* Oldest +* Last Login + +### Layout Options + +Users are displayed in Grid format by default, showing: + +* Initials, full name, and group membership. +* Login status (for example, “Inactive” label). +* Last login time (if applicable). + +Click the table/grid icon (top-right corner) to switch to a more compact, column-based layout. + +## Default User Groups + +By default, the User Groups available to new users are **Administrators**, **Editors**, **Sensitive Data**, **Translators,** and **Writers**. + +* **Administrators**: Can do anything when editing nodes in the content section (has all permissions). +* **Editors**: Allowed to create and publish content items or nodes on the website without approval from others or restrictions (has permissions to **Public Access**, **Rollback**, **Browse Node**, **Create Content Template**, **Delete**, **Create**, **Publish**, **Unpublish**, **Update**, **Copy**, **Move** and **Sort**). +* **Sensitive data**: Any users added to this User group will have access to view any data marked as sensitive. Learn more about this feature in the [Sensitive Data](../../../reference/security/sensitive-data-on-members.md) article. +* **Translators**: These are used for translating your website. Translators are allowed to browse and update nodes as well as grant dashboard access. Translations of site pages must be reviewed by others before publication (has permissions to **Browse Node** and **Update**). +* **Writers**: Allowed to browse nodes, create nodes, and request for publication of items. Not allowed to publish directly without someone else's approval like an Editor (has permissions to **Browse Node**, **Create**, **Send to Publish,** and **Update**). + +## Creating a User Group + +You can also create your own custom User Groups and add properties and tabs as you would with Document Types and Member Types. + +1. Go to the **Users** section. +2. Select **User Groups**. +3. Click **Create**. + +![User Groups Menu](../images/user-groups-menu-v16.png) + +### User Group Parameters + +![Create User Group](../images/user-groups-v16.png) + +Enter the information about the User Group and settings for custom properties: + +* **Name**: The name of the User Group. +* **Alias**: Used to reference the User Group in code - the alias will be auto-generated based on the name. +* **Assign access**: Define which sections and languages the users will have access to. Also, if the users should have access to only some or all content and media. +* **Default Permissions**: Select the default permissions granted to users of the User Group. +* **Granular permissions**: Define a specific node the users in the group should have access to. + +## User Permissions + +Depending on which User Group a user is added to, each user has a set of permissions associated with their accounts. These permissions either enable or disable a user's ability to perform their associated function. + +The available user Permissions are defined under **Default Permissions** in the User group. + +![Default permissions](../images/default-permissions-v16.png) + +## Granular Permissions + +As an addition to the Default Permissions, it is also possible to add more granular permissions on a User Group level. + +![Granular permissions](../images/granular-permissions.png) + +With the **Documents** permission, you can define granular permissions on specific documents. This is useful when a User Group should only have limited access to a certain page on the website. Clicking **Add** opens a dialog where you can choose between documents from the Content section. + +With the **Document Property Values** permission, you can define both read and write permissions for individual properties on a Document Type. This is useful if a User Group should have limited access to edit the content on a specific type of document. Clicking **Add** opens a dialog where you select a Document Type, choose a Property, and, finally, set the read and write permissions. + +### Setting User Permissions + +When a new user is created, you can set specific permissions for that user on different domains and subdomains. You can also set permissions on different User Groups, even for the default types. + +## Technical + +As a developer, you are only able to leverage your website from the backoffice when you build on the Users section of Umbraco. This is because the Users section is restricted to the Umbraco backoffice. + +## [Managing Forms Security](https://docs.umbraco.com/umbraco-forms/developer/security) + +Umbraco Forms has a backoffice security model integrated with Umbraco Users. You can manage the details in the **Users** section of the backoffice, within a tree named **Forms Security**. diff --git a/17/umbraco-cms/fundamentals/data/users/api-users.md b/17/umbraco-cms/fundamentals/data/users/api-users.md new file mode 100644 index 00000000000..6aca71f7952 --- /dev/null +++ b/17/umbraco-cms/fundamentals/data/users/api-users.md @@ -0,0 +1,29 @@ +--- +description: This guide will explain the concept of API Users, how they differ from regular Users, and how to define them +--- + +# API Users + +API Users allow for authorizing [external access](../../../reference/management-api/external-access.md) to the Management API. + +An API User is identical to a [regular User](README.md) except for one thing: It has no password. In fact, API Users are not allowed to log into the backoffice like regular Users. + +Instead, API Users hold the Client Credentials used to authorize against the Management API. When an external source authorizes using Client Credentials, it effectively assumes the identity of the API User. + +Since API Users are identical to regular Users their backoffice access can be controlled in the same way. This allows for imposing detailed access control on the external sources connected to the Management API. + +![An API User in the backoffice](../images/api-user.png) + +{% hint style="info" %} +Client IDs for API Users are explicitly prefixed with `umbraco-back-office-`. This guards against API Users accidentally taking over one of the Client IDs used by the Umbraco core. +{% endhint %} + +## Creating an API User + +To create an API User: + +1. Go to the **Users** section in the backoffice. +2. Select **Create -> API User**. +3. Enter the **Name** and **Email** of the new API user. +4. Select which **User group** the new user should be added to. +5. Click **Create user**. diff --git a/17/umbraco-cms/fundamentals/design/README.md b/17/umbraco-cms/fundamentals/design/README.md new file mode 100644 index 00000000000..9855ffb0c57 --- /dev/null +++ b/17/umbraco-cms/fundamentals/design/README.md @@ -0,0 +1,21 @@ +# Design + +## [Templates](templates/README.md) + +Creating, managing, and reusing templates in Umbraco. + +## [Rendering content](rendering-content.md) + +Querying and rendering published content. + +## [Rendering media](rendering-media.md) + +Querying and rendering media items. + +## [Partial Views](partial-views.md) + +Working with partial views in Umbraco's templates. + +## [Stylesheets and JavaScript](stylesheets-javascript.md) + +Working with CSS and JavaScript in Umbraco's templates. diff --git a/17/umbraco-cms/fundamentals/design/images/1-creating-stylesheet.png b/17/umbraco-cms/fundamentals/design/images/1-creating-stylesheet.png new file mode 100644 index 00000000000..46a9328fea0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/1-creating-stylesheet.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/10-reference-script-v9.png b/17/umbraco-cms/fundamentals/design/images/10-reference-script-v9.png new file mode 100644 index 00000000000..14202a63874 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/10-reference-script-v9.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/10-reference-script.png b/17/umbraco-cms/fundamentals/design/images/10-reference-script.png new file mode 100644 index 00000000000..4aabb9cd603 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/10-reference-script.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/2-rte-editor.png b/17/umbraco-cms/fundamentals/design/images/2-rte-editor.png new file mode 100644 index 00000000000..c09094a7d33 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/2-rte-editor.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p2.png b/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p2.png new file mode 100644 index 00000000000..2e2c1713de4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p2.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p3.png b/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p3.png new file mode 100644 index 00000000000..55f70239042 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/3-rte-editor-p3.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/4-link-css-v9.png b/17/umbraco-cms/fundamentals/design/images/4-link-css-v9.png new file mode 100644 index 00000000000..9a9a2d7f9d2 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/4-link-css-v9.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/4-link-css.png b/17/umbraco-cms/fundamentals/design/images/4-link-css.png new file mode 100644 index 00000000000..ffdf9a237fa Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/4-link-css.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/5-rtesheet.png b/17/umbraco-cms/fundamentals/design/images/5-rtesheet.png new file mode 100644 index 00000000000..8abfe1a78c1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/5-rtesheet.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/6-rte-connect-sheet.png b/17/umbraco-cms/fundamentals/design/images/6-rte-connect-sheet.png new file mode 100644 index 00000000000..ef4e6e1c09c Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/6-rte-connect-sheet.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/7-content-rte.png b/17/umbraco-cms/fundamentals/design/images/7-content-rte.png new file mode 100644 index 00000000000..db8e18048d0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/7-content-rte.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/8-create-js.png b/17/umbraco-cms/fundamentals/design/images/8-create-js.png new file mode 100644 index 00000000000..1290096e6e6 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/8-create-js.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/9-myscript.png b/17/umbraco-cms/fundamentals/design/images/9-myscript.png new file mode 100644 index 00000000000..000ee142a1b Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/9-myscript.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/Partial-Views-folder.png b/17/umbraco-cms/fundamentals/design/images/Partial-Views-folder.png new file mode 100644 index 00000000000..fb64d9dc65f Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/Partial-Views-folder.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/button-v8.png b/17/umbraco-cms/fundamentals/design/images/button-v8.png new file mode 100644 index 00000000000..2d4e00f98b8 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/button-v8.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/button.png b/17/umbraco-cms/fundamentals/design/images/button.png new file mode 100644 index 00000000000..bb6de535ee1 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/button.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/created-partial-view-from-snippet.png b/17/umbraco-cms/fundamentals/design/images/created-partial-view-from-snippet.png new file mode 100644 index 00000000000..55f96243d65 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/created-partial-view-from-snippet.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-from-snippet.png b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-from-snippet.png new file mode 100644 index 00000000000..c8a3bb9a69a Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-from-snippet.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-without-macro.png b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-without-macro.png new file mode 100644 index 00000000000..9c8a77f8ee4 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file-without-macro.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file.png b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file.png new file mode 100644 index 00000000000..d7486429b06 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/created-partial-view-macro-file.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/created-partial-view.png b/17/umbraco-cms/fundamentals/design/images/created-partial-view.png new file mode 100644 index 00000000000..9f38a626f45 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/created-partial-view.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/creating-partial-view-macro-files.png b/17/umbraco-cms/fundamentals/design/images/creating-partial-view-macro-files.png new file mode 100644 index 00000000000..38d0eddacd0 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/creating-partial-view-macro-files.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/creating-partial-view.png b/17/umbraco-cms/fundamentals/design/images/creating-partial-view.png new file mode 100644 index 00000000000..d81a6916a5d Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/creating-partial-view.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/dialog.png b/17/umbraco-cms/fundamentals/design/images/dialog.png new file mode 100644 index 00000000000..d79cecce0b7 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/dialog.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/folder.png b/17/umbraco-cms/fundamentals/design/images/folder.png new file mode 100644 index 00000000000..6832f2efa93 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/folder.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/language-fallback.png b/17/umbraco-cms/fundamentals/design/images/language-fallback.png new file mode 100644 index 00000000000..bb48e169036 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/language-fallback.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/partial-views-in-directory.png b/17/umbraco-cms/fundamentals/design/images/partial-views-in-directory.png new file mode 100644 index 00000000000..df2e5682b03 Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/partial-views-in-directory.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/query-button.png b/17/umbraco-cms/fundamentals/design/images/query-button.png new file mode 100644 index 00000000000..373fbe4391b Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/query-button.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/query-v8.png b/17/umbraco-cms/fundamentals/design/images/query-v8.png new file mode 100644 index 00000000000..d3074f19d3a Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/query-v8.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/query-v9.png b/17/umbraco-cms/fundamentals/design/images/query-v9.png new file mode 100644 index 00000000000..53dd76262eb Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/query-v9.png differ diff --git a/17/umbraco-cms/fundamentals/design/images/query.png b/17/umbraco-cms/fundamentals/design/images/query.png new file mode 100644 index 00000000000..cc517bf09bc Binary files /dev/null and b/17/umbraco-cms/fundamentals/design/images/query.png differ diff --git a/17/umbraco-cms/fundamentals/design/partial-views.md b/17/umbraco-cms/fundamentals/design/partial-views.md new file mode 100644 index 00000000000..c363e80d7cb --- /dev/null +++ b/17/umbraco-cms/fundamentals/design/partial-views.md @@ -0,0 +1,115 @@ +--- +description: Information on working with partial views in Umbraco +--- + +# Partial Views + +A Partial View (`.cshtml` file) is a regular view that can be used multiple times throughout your site. A Partial View is used to break up large markup files into smaller components such as header, footer, navigation menu, etc. It helps to reduce the duplication of code. A partial view renders a view within the parent view. + +## Partial Views in the Backoffice + +You can create and edit partial views in the **Partial Views** folder from the **Settings** section of the Backoffice. + +![Creating a new partial view](templates/images/create-partial.png) + +In the **Create** menu, there are three options available: + +* New empty partial view +* New partial view from snippet +* Folder (for keeping the partial views organized) + +## Creating a Partial View + +To create a partial view: + +1. Go to the **Settings** section in the Umbraco backoffice. +2. Click **...** next to the **Partial Views** folder. +3. Choose **Create**. +4. Select **New empty partial view**. +5. Enter a partial view name. +6. Click the **Save** button. You will now see the partial view markup in the backoffice editor. + +
Created partial view

Created partial view

+ +By default, the partial views are saved in the `Views/Partials` folder in the solution. + +![Partial View folder in the project directory](images/partial-views-in-directory.png) + +## Creating a Partial View from Snippet + +To create a partial view from the snippet: + +1. Go to the **Settings** section in the Umbraco backoffice. +2. Click **...** next to the **Partial Views** folder. +3. Choose **Create**. +4. Select **New empty partial view from snippet**. +5. Select the snippet you want to create a partial view for and enter a partial view name. The code snippet you selected is displayed in the backoffice editor. +6. Click the **Save** button. + +

Created partial view from snippet

+ +Umbraco provides the following partial view snippets: + +* Empty - Creates an empty partial view file. +* Breadcrumb - Creates a breadcrumb of parents using the `Ancestors()` method to generate links in an unordered HTML list. It displays the name of the current page without a link. +* Edit Profile - Creates a Member profile model that can be edited. +* List Ancestors From Current Page - Displays a list of links to the parents of the current page using the `Ancestors()` method to generate links in an unordered HTML list. It displays the name of the current page without a link. +* List Child Pages From Current Page - Displays a list of links to the children of the current page using the `Children()` method to generate links in an unordered HTML list. +* List Child Pages Ordered By Date - Displays a list of links to the children of the current page using the `Children()` method to generate links in an unordered HTML list. The pages are sorted by the creation date in a descending order using the `OrderByDescending()` method. +* List Child Pages Ordered By Name - Displays a list of links to the children of the current page using the `Children()` method to generate links in an unordered HTML list. The pages are sorted by the page name using the `OrderBy()` method. +* List Child Pages With DocType - Displays only the children of a certain Document Type. +* List Descendants From Current Page - Displays a list of links for every page below the current page in an unordered HTML list. +* Login - Displays a login form. +* Login Status - Displays the user name if the user is logged in. +* Multinode Tree-picker - Lists the items from a Multinode tree picker using the picker's default settings. +* Navigation - Displays a list of links of the pages under the top-most page in the Content tree. It also highlights the currently active page/section in the navigation menu. +* Register Member - Displays a Member registration form. It will only display the properties marked as **Member can edit** on the **Info** tab of the Member Type. +* Site Map - Displays a list of links of all the visible pages of the site using the `Traverse()` method to select and display the markup and links as nested unordered HTML lists. + +## Creating a Folder + +To create a folder: + +1. Go to the **Settings** section in the Umbraco backoffice. +2. Click **...** next to the **Partial Views** folder. +3. Choose **Create**. +4. Select **Folder**. +5. Enter a folder name. +6. Click the **Create** button. + +
+ +
Created folder

Created folder

+ +
+ +## Rendering a Partial View + +To render the created partial view into any template, use any of these helper methods: `@Html.PartialAsync`, `@Html.Partial()`, or `@Html.RenderPartial()` + +```csharp +@using Umbraco.Cms.Web.Common.PublishedModels; +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels; +@{ + Layout = null; +} + +@await Html.PartialAsync("Login") + +@Html.Partial("Login") + +@{ + Html.RenderPartial("Login"); +} +``` + +### Related Articles + +* [Using MVC Partial Views in Umbraco](../../reference/templating/mvc/partial-views.md) + +### Video Materials + +{% embed url="https://www.youtube.com/watch?ab_channel=UmbracoLearningBase&v=RcYM_DJ-JnQ" %} +Getting started with Umbraco: Partial Views +{% endembed %} diff --git a/17/umbraco-cms/fundamentals/design/rendering-content.md b/17/umbraco-cms/fundamentals/design/rendering-content.md new file mode 100644 index 00000000000..c76382ca502 --- /dev/null +++ b/17/umbraco-cms/fundamentals/design/rendering-content.md @@ -0,0 +1,110 @@ +# Rendering Content + +_The primary task of any template is to render the values of the current page or the result of a query against the content cache._ + +## Display a value in your template view + +Each property in your [Document Type](../data/defining-content/#what-is-a-document-type) has an alias, this is used to specify where in the template view to display the value. + +```html +

@Model.Value("pageTitle")

+
@Model.Value("bodyContent")
+ +``` + +### Specifying types of data + +You can specify the type of data being returned to help you format the value for display. + +In our example, we have a string, a date and some rich text: + +```html +

@(Model.Value("pageTitle"))

+
@(Model.Value("bodyContent"))
+

Article date:

+``` + +{% hint style="info" %} +To use `IHtmlEncodedString` as the typed value, add the `@using Umbraco.Cms.Core.Strings;` directive. +{% endhint %} + +### Using ModelsBuilder + +```html +

@Model.PageTitle

+
@Model.BodyContent
+ +``` + +### Using fall-back methods + +The `.Value()` method has a number of optional parameters that support scenarios where we want to "fall-back" to some other content. + +To use the `fallback` type, add the `@using Umbraco.Cms.Core.Models.PublishedContent;` directive. + +* To display a static, default value when a property value is not populated on the current content item: + + ```csharp + @Model.Value("pageTitle", fallback: Fallback.ToDefaultValue, defaultValue: new HtmlString("Default page title")) + ``` +* A second supported method is to traverse up the tree ancestors to try to find a value. If the current content item isn't populated for a property, we can retrieve the value from the parent, grand-parent, or a higher ancestor in the tree. The first ancestor encountered that has a value will be the one returned. + + ```csharp + @Model.Value("pageTitle", fallback: Fallback.ToAncestors) + ``` +* If developing a multi-lingual site and fall-back languages\* have been configured, the third method available is to retrieve a value for a different language, if the language we are requesting does not have content populated. In this way, we could render a field containing French content for a property if it's populated in that language, and if not, default to English. + + ```csharp + @Model.Value("pageTitle", "fr", fallback: Fallback.ToLanguage) + ``` +* We can also combine these options to create some more sophisticated scenarios. For example, we might want to fall-back via language first, and if that doesn't find any populated content, then try to find a value by traversing through the ancestors of the tree. We can do that using the following syntax, with the order of the fall-back options provided determining the order that content will be attempted to be retrieved: + + ```csharp + @Model.Value("pageTitle", "fr", fallback: Fallback.To(Fallback.Language, Fallback.Ancestors)) + ``` +* In this example, we are looking for content firstly on the current node for the default language, and if not found we'll search through the ancestors. If failing to find any populated value from them, we'll use the provided default: + + ```csharp + @Model.Value("pageTitle", fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), defaultValue: new HtmlString("Default page title")) + ``` +* We can use similar overloads when working with ModelsBuilder, for example: + + ```csharp + // For projects created before January 2020 + @Model.Value(x => x.PageTitle, "fr", fallback: Fallback.ToLanguage) + @Model.Value(x => x.PageTitle, fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), defaultValue: new HtmlString("Default page title")) + + // For projects created after January 2020 + @Model.ValueFor(x => x.PageTitle, "fr", fallback: Fallback.ToLanguage) + @Model.ValueFor(x => x.PageTitle, fallback: Fallback.To(Fallback.Ancestors, Fallback.DefaultValue), defaultValue: new HtmlString("Default page title")) + ``` + + * Fall-back languages can be configured via the **Languages** tree within the **Settings** section. + * Each language can optionally be provided with a fall-back language, that will be used when content is not populated for the language requested and the appropriate overload parameters are provided. + * It is possible to chain these language fall-backs, so requesting content for Portuguese, could fall-back to Spanish and then on to English. + + ![Configuring fall-back languages](images/language-fallback.png) + +## Query content + +In many cases, you want to do more than display values from the current page, like creating a list of pages in the navigation. You can access content relative to the current page using methods such as `Children()`, `Descendants()` & `Ancestors()`. Explore the [full list of methods](../../reference/templating/mvc/querying.md#traversing). + +You can do this by querying content relative to your current page in template views: + +```csharp +
    + @foreach (var child in Model.Children()) + { +
  • @child.Name()
  • + } +
+``` + +You can use the Query Builder in the template editor to build more advanced queries. ![Query button](../../../../10/umbraco-cms/fundamentals/design/images/button-v8.png) + +![Query helper](../../../../10/umbraco-cms/fundamentals/design/images/query-v9.png) + +### More information + +* [Razor examples](../../reference/templating/mvc/examples.md) +* [Querying](../../reference/templating/mvc/querying.md) diff --git a/17/umbraco-cms/fundamentals/design/rendering-media.md b/17/umbraco-cms/fundamentals/design/rendering-media.md new file mode 100644 index 00000000000..e339f90bf25 --- /dev/null +++ b/17/umbraco-cms/fundamentals/design/rendering-media.md @@ -0,0 +1,147 @@ +--- +description: "Info on rendering media items and imaging cropping" +--- + +# Rendering media + +_Templates (Views) can access items in the_ [_Media library_](../data/creating-media/) _to assist in displaying rich content like galleries_. + +In the following examples, we will be looking at rendering an `Image`. + +Image is only one of the 'types' of Media in Umbraco. The same principles apply to all Media Types. The properties available to render will be different from Media Type to Media Type. For example, a `File` will not have a Width property. + +## Rendering a media item + +A media item is not only a reference to a static file. Like content, it is a collection of fields, such as width, height, and file path. This means that accessing and rendering media in a Template is similar to rendering content. + +### Example 1: Accessing a Media Image IPublishedContent item based on the ID + +An uploaded image in the Media library is based on the Media Type `Image` which has a number of standard properties: + +* Name +* Width & Height +* Size +* Type (based on file extension) +* UmbracoFile (the path to the file or JSON data containing crop information) + +These standard properties are pre-populated and set during the upload process. For example, this means that the width and height are calculated for you. + +If you want to add further properties to use with your Media Item, edit the Image Media Type under **Settings**. In this example, we are going to retrieve an image from the Media section. Then we will render out an `img` tag using the URL of the media item and use the Name as the value for the `alt` attribute. + +{% hint style="info" %} +The Media item in the following sample will use a sample Guid (`55240594-b265-4fc2-b1c1-feffc5cf9571`). This example is **not using Models Builder**. +{% endhint %} + +```csharp +@{ + // The Umbraco Helper has a Media method that will retrieve a Media Item by Guid in the form of IPublishedContent. In this example, the Media Item has a Guid of 55240594-b265-4fc2-b1c1-feffc5cf9571 + + var mediaItem = Umbraco.Media(Guid.Parse("55240594-b265-4fc2-b1c1-feffc5cf9571")); + + if (mediaItem != null) + { + // To get the URL for your media item, you use the Url method: + var url = mediaItem.Url(); + // to read a property by alias + var imageHeight = mediaItem.Value("umbracoHeight"); + var imageWidth = mediaItem.Value("umbracoWidth"); + var orientationCssClass = imageWidth > imageHeight ? "img-landscape" : "img-portrait"; + + @mediaItem.Name + } +} +``` + +But wait a second, Umbraco comes with [Models Builder](../../reference/templating/modelsbuilder/). This means that you can use strongly typed models for your media items if Models Builder is enabled (which it is by default). + +### Example 2: Accessing a Media Image ModelsBuilder item based on the ID + +As with example one, we are accessing a MediaType `image` using the same Guid assumption. + +```csharp +@{ + // Since the Image Model generated by Modelsbuilder is a compatible type to IPublishedContent we can use the 'as' operator to convert it into the ModelsBuilder Umbraco.Cms.Web.Common.PublishedModels.Image class + var mediaItemAsImage = Umbraco.Media(Guid.Parse("55240594-b265-4fc2-b1c1-feffc5cf9571")) as Image; + if (mediaItemAsImage != null) + { + // you could add this as an extension method to the Umbraco.Cms.Web.Common.PublishedModels.Image class + var orientationCssClass = mediaItemAsImage.UmbracoWidth > mediaItemAsImage.UmbracoHeight ? "img-landscape" : "img-portrait"; + + @mediaItemAsImage.Name + } +} +``` + +{% hint style="info" %} +It is always worth having null-checks around your code when retrieving media in case the conversion fails or Media() returns null. This makes your code more robust. +{% endhint %} + +## Working with Video files + +If you upload a video file (such as `.mp4`) to the Media library, Umbraco will store it as a Video Media Type by default. Unlike images, video files won’t include properties like `umbracoWidth` or `umbracoHeight`, but you can still retrieve the media item and render it using the `