= [
+ ...entrypoints,
+ //#if IncludeExample
+ ...dashboards,
+ //#endif
+];
diff --git a/templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts b/templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts
new file mode 100644
index 0000000000..287464086e
--- /dev/null
+++ b/templates/UmbracoExtension/Client/src/dashboards/dashboard.element.ts
@@ -0,0 +1,176 @@
+import { LitElement, css, html, customElement, state } from "@umbraco-cms/backoffice/external/lit";
+import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api";
+import { UmbracoExtensionService, UserModel } from "../api";
+import { UUIButtonElement } from "@umbraco-cms/backoffice/external/uui";
+import { UMB_NOTIFICATION_CONTEXT, UmbNotificationContext } from "@umbraco-cms/backoffice/notification";
+import { UMB_CURRENT_USER_CONTEXT, UmbCurrentUserModel } from "@umbraco-cms/backoffice/current-user";
+
+@customElement('example-dashboard')
+export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
+
+ @state()
+ private _yourName: string | undefined = "Press the button!";
+
+ @state()
+ private _timeFromMrWolf: Date | undefined;
+
+ @state()
+ private _serverUserData: UserModel | undefined = undefined;
+
+ @state()
+ private _contextCurrentUser: UmbCurrentUserModel | undefined = undefined;
+
+ constructor() {
+ super();
+
+ this.consumeContext(UMB_NOTIFICATION_CONTEXT, (notificationContext) => {
+ this.#notificationContext = notificationContext;
+ });
+
+ this.consumeContext(UMB_CURRENT_USER_CONTEXT, (currentUserContext) => {
+
+ // When we have the current user context
+ // We can observe properties from it, such as the current user or perhaps just individual properties
+ // When the currentUser object changes we will get notified and can reset the @state properrty
+ this.observe(currentUserContext.currentUser, (currentUser) => {
+ this._contextCurrentUser = currentUser;
+ });
+ });
+ }
+
+ #notificationContext: UmbNotificationContext | undefined = undefined;
+
+ #onClickWhoAmI = async (ev: Event) => {
+ const buttonElement = ev.target as UUIButtonElement;
+ buttonElement.state = "waiting";
+
+ const { data, error } = await UmbracoExtensionService.whoAmI();
+
+ if (error) {
+ buttonElement.state = "failed";
+ console.error(error);
+ return;
+ }
+
+ if (data !== undefined) {
+ this._serverUserData = data;
+ buttonElement.state = "success";
+ }
+
+ if (this.#notificationContext) {
+ this.#notificationContext.peek("warning", {
+ data: {
+ headline: `You are ${this._serverUserData?.name}`,
+ message: `Your email is ${this._serverUserData?.email}`,
+ }
+ })
+ }
+ }
+
+ #onClickWhatsTheTimeMrWolf = async (ev: Event) => {
+ const buttonElement = ev.target as UUIButtonElement;
+ buttonElement.state = "waiting";
+
+ // Getting a string - should I expect a datetime?!
+ const { data, error } = await UmbracoExtensionService.whatsTheTimeMrWolf();
+
+ if (error) {
+ buttonElement.state = "failed";
+ console.error(error);
+ return;
+ }
+
+ if (data !== undefined) {
+ this._timeFromMrWolf = new Date(data);
+ buttonElement.state = "success";
+ }
+ }
+
+ #onClickWhatsMyName = async (ev: Event) => {
+ const buttonElement = ev.target as UUIButtonElement;
+ buttonElement.state = "waiting";
+
+ const { data, error } = await UmbracoExtensionService.whatsMyName();
+
+ if (error) {
+ buttonElement.state = "failed";
+ console.error(error);
+ return;
+ }
+
+ this._yourName = data;
+ buttonElement.state = "success";
+ }
+
+ render() {
+ return html`
+
+ [Server]
+ ${this._serverUserData?.email ? this._serverUserData.email : 'Press the button!'}
+
+ ${this._serverUserData?.groups.map(group => html`- ${group.name}
`)}
+
+
+ Who am I?
+
+ This endpoint gets your current user from the server and displays your email and list of user groups.
+ It also displays a Notification with your details.
+
+
+
+ [Server]
+ ${this._yourName }
+
+ Whats my name?
+
+ This endpoint has a forced delay to show the button 'waiting' state for a few seconds before completing the request.
+
+
+
+ [Server]
+ ${this._timeFromMrWolf ? this._timeFromMrWolf.toLocaleString() : 'Press the button!'}
+
+ Whats the time Mr Wolf?
+
+ This endpoint gets the current date and time from the server.
+
+
+
+ [Context]
+ Current user email: ${this._contextCurrentUser?.email}
+ This is the JSON object available by consuming the 'UMB_CURRENT_USER_CONTEXT' context:
+ ${JSON.stringify(this._contextCurrentUser, null, 2)}
+
+ `;
+ }
+
+ static styles = [
+ css`
+ :host {
+ display: grid;
+ gap: var(--uui-size-layout-1);
+ padding: var(--uui-size-layout-1);
+ grid-template-columns: 1fr 1fr 1fr;
+ }
+
+ uui-box {
+ margin-bottom: var(--uui-size-layout-1);
+ }
+
+ h2 {
+ margin-top:0;
+ }
+
+ .wide {
+ grid-column: span 3;
+ }
+ `];
+}
+
+export default ExampleDashboardElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'example-dashboard': ExampleDashboardElement;
+ }
+}
diff --git a/templates/UmbracoExtension/Client/src/dashboards/manifest.ts b/templates/UmbracoExtension/Client/src/dashboards/manifest.ts
new file mode 100644
index 0000000000..a020e3ab2c
--- /dev/null
+++ b/templates/UmbracoExtension/Client/src/dashboards/manifest.ts
@@ -0,0 +1,18 @@
+export const manifests: Array = [
+ {
+ name: "Umbraco ExtensionDashboard",
+ alias: "Umbraco.Extension.Dashboard",
+ type: 'dashboard',
+ js: () => import("./dashboard.element"),
+ meta: {
+ label: "Example Dashboard",
+ pathname: "example-dashboard"
+ },
+ conditions: [
+ {
+ alias: 'Umb.Condition.SectionAlias',
+ match: 'Umb.Section.Content',
+ }
+ ],
+ }
+];
diff --git a/templates/UmbracoExtension/Client/src/entrypoints/entrypoint.ts b/templates/UmbracoExtension/Client/src/entrypoints/entrypoint.ts
new file mode 100644
index 0000000000..65796c3202
--- /dev/null
+++ b/templates/UmbracoExtension/Client/src/entrypoints/entrypoint.ts
@@ -0,0 +1,38 @@
+import { UmbEntryPointOnInit, UmbEntryPointOnUnload } from '@umbraco-cms/backoffice/extension-api';
+//#if IncludeExample
+import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
+import { client } from '../api';
+//#endif
+
+// load up the manifests here
+export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => {
+
+ console.log('Hello from my extension 🎉');
+ //#if IncludeExample
+ // Will use only to add in Open API config with generated TS OpenAPI HTTPS Client
+ // Do the OAuth token handshake stuff
+ _host.consumeContext(UMB_AUTH_CONTEXT, async (authContext) => {
+
+ // Get the token info from Umbraco
+ const config = authContext.getOpenApiConfiguration();
+
+ client.setConfig({
+ baseUrl: config.base,
+ credentials: config.credentials
+ });
+
+ // For every request being made, add the token to the headers
+ // Can't use the setConfig approach above as its set only once and
+ // tokens expire and get refreshed
+ client.interceptors.request.use(async (request, _options) => {
+ const token = await config.token();
+ request.headers.set('Authorization', `Bearer ${token}`);
+ return request;
+ });
+ });
+ //#endif
+};
+
+export const onUnload: UmbEntryPointOnUnload = (_host, _extensionRegistry) => {
+ console.log('Goodbye from my extension 👋');
+};
diff --git a/templates/UmbracoExtension/Client/src/entrypoints/manifest.ts b/templates/UmbracoExtension/Client/src/entrypoints/manifest.ts
new file mode 100644
index 0000000000..5dcda9de89
--- /dev/null
+++ b/templates/UmbracoExtension/Client/src/entrypoints/manifest.ts
@@ -0,0 +1,8 @@
+export const manifests: Array = [
+ {
+ name: "Umbraco ExtensionEntrypoint",
+ alias: "Umbraco.Extension.Entrypoint",
+ type: "backofficeEntryPoint",
+ js: () => import("./entrypoint"),
+ }
+];
diff --git a/templates/UmbracoExtension/Client/tsconfig.json b/templates/UmbracoExtension/Client/tsconfig.json
new file mode 100644
index 0000000000..1b3364784e
--- /dev/null
+++ b/templates/UmbracoExtension/Client/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "experimentalDecorators": true,
+ "useDefineForClassFields": false,
+ "module": "ESNext",
+ "lib": [ "ES2020", "DOM", "DOM.Iterable" ],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+
+ "types": [ "@umbraco-cms/backoffice/extension-types" ]
+ },
+ "include": [ "src" ]
+}
diff --git a/templates/UmbracoExtension/Client/vite.config.ts b/templates/UmbracoExtension/Client/vite.config.ts
new file mode 100644
index 0000000000..5232076b8c
--- /dev/null
+++ b/templates/UmbracoExtension/Client/vite.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: "src/bundle.manifests.ts", // Bundle registers one or more manifests
+ formats: ["es"],
+ fileName: "umbraco-extension",
+ },
+ outDir: "../wwwroot/App_Plugins/UmbracoExtension", // your web component will be saved in this location
+ emptyOutDir: true,
+ sourcemap: true,
+ rollupOptions: {
+ external: [/^@umbraco/],
+ },
+ }
+});
diff --git a/templates/UmbracoExtension/Composers/UmbracoExtensionApiComposer.cs b/templates/UmbracoExtension/Composers/UmbracoExtensionApiComposer.cs
new file mode 100644
index 0000000000..481e1d19bb
--- /dev/null
+++ b/templates/UmbracoExtension/Composers/UmbracoExtensionApiComposer.cs
@@ -0,0 +1,73 @@
+using Asp.Versioning;
+using Microsoft.AspNetCore.Mvc.ApiExplorer;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.SwaggerGen;
+using Umbraco.Cms.Core.Composing;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Api.Management.OpenApi;
+using Umbraco.Cms.Api.Common.OpenApi;
+
+namespace Umbraco.Extension.Composers
+{
+ public class UmbracoExtensionApiComposer : IComposer
+ {
+ public void Compose(IUmbracoBuilder builder)
+ {
+
+ builder.Services.AddSingleton();
+
+ builder.Services.Configure(opt =>
+ {
+ // Related documentation:
+ // https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-backoffice-api
+ // https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-backoffice-api/adding-a-custom-swagger-document
+ // https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-backoffice-api/versioning-your-api
+ // https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-backoffice-api/access-policies
+
+ // Configure the Swagger generation options
+ // Add in a new Swagger API document solely for our own package that can be browsed via Swagger UI
+ // Along with having a generated swagger JSON file that we can use to auto generate a TypeScript client
+ opt.SwaggerDoc(Constants.ApiName, new OpenApiInfo
+ {
+ Title = "Umbraco ExtensionBackoffice API",
+ Version = "1.0",
+ // Contact = new OpenApiContact
+ // {
+ // Name = "Some Developer",
+ // Email = "you@company.com",
+ // Url = new Uri("https://company.com")
+ // }
+ });
+
+ // Enable Umbraco authentication for the "Example" Swagger document
+ // PR: https://github.com/umbraco/Umbraco-CMS/pull/15699
+ opt.OperationFilter();
+ });
+ }
+
+ public class UmbracoExtensionOperationSecurityFilter : BackOfficeSecurityRequirementsOperationFilterBase
+ {
+ protected override string ApiName => Constants.ApiName;
+ }
+
+ // This is used to generate nice operation IDs in our swagger json file
+ // So that the gnerated TypeScript client has nice method names and not too verbose
+ // https://docs.umbraco.com/umbraco-cms/tutorials/creating-a-backoffice-api/umbraco-schema-and-operation-ids#operation-ids
+ public class CustomOperationHandler : OperationIdHandler
+ {
+ public CustomOperationHandler(IOptions apiVersioningOptions) : base(apiVersioningOptions)
+ {
+ }
+
+ protected override bool CanHandle(ApiDescription apiDescription, ControllerActionDescriptor controllerActionDescriptor)
+ {
+ return controllerActionDescriptor.ControllerTypeInfo.Namespace?.StartsWith("Umbraco.Extension.Controllers", comparisonType: StringComparison.InvariantCultureIgnoreCase) is true;
+ }
+
+ public override string Handle(ApiDescription apiDescription) => $"{apiDescription.ActionDescriptor.RouteValues["action"]}";
+ }
+ }
+}
diff --git a/templates/UmbracoExtension/Constants.cs b/templates/UmbracoExtension/Constants.cs
new file mode 100644
index 0000000000..9fc6796da1
--- /dev/null
+++ b/templates/UmbracoExtension/Constants.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Extension
+{
+ public class Constants
+ {
+ public const string ApiName = "umbracoextension";
+ }
+}
diff --git a/templates/UmbracoExtension/Controllers/UmbracoExtensionApiController.cs b/templates/UmbracoExtension/Controllers/UmbracoExtensionApiController.cs
new file mode 100644
index 0000000000..2f62ec2785
--- /dev/null
+++ b/templates/UmbracoExtension/Controllers/UmbracoExtensionApiController.cs
@@ -0,0 +1,49 @@
+using Asp.Versioning;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+#if IncludeExample
+using Umbraco.Cms.Core.Models.Membership;
+using Umbraco.Cms.Core.Security;
+#endif
+
+namespace Umbraco.Extension.Controllers
+{
+ [ApiVersion("1.0")]
+ [ApiExplorerSettings(GroupName = "Umbraco.Extension")]
+ public class UmbracoExtensionApiController : UmbracoExtensionApiControllerBase
+ {
+#if IncludeExample
+ private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
+
+ public UmbracoExtensionApiController(IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
+ {
+ _backOfficeSecurityAccessor = backOfficeSecurityAccessor;
+ }
+#endif
+
+ [HttpGet("ping")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public string Ping() => "Pong";
+#if IncludeExample
+
+ [HttpGet("whatsTheTimeMrWolf")]
+ [ProducesResponseType(typeof(DateTime), 200)]
+ public DateTime WhatsTheTimeMrWolf() => DateTime.Now;
+
+ [HttpGet("whatsMyName")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public string WhatsMyName()
+ {
+ // So we can see a long request in the dashboard with a spinning progress wheel
+ Thread.Sleep(2000);
+
+ var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser;
+ return currentUser?.Name ?? "I have no idea who you are";
+ }
+
+ [HttpGet("whoAmI")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public IUser? WhoAmI() => _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser;
+#endif
+ }
+}
diff --git a/templates/UmbracoExtension/Controllers/UmbracoExtensionApiControllerBase.cs b/templates/UmbracoExtension/Controllers/UmbracoExtensionApiControllerBase.cs
new file mode 100644
index 0000000000..3e5a5e14a0
--- /dev/null
+++ b/templates/UmbracoExtension/Controllers/UmbracoExtensionApiControllerBase.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Cms.Api.Common.Attributes;
+using Umbraco.Cms.Web.Common.Authorization;
+using Umbraco.Cms.Web.Common.Routing;
+
+namespace Umbraco.Extension.Controllers
+{
+ [ApiController]
+ [BackOfficeRoute("umbracoextension/api/v{version:apiVersion}")]
+ [Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
+ [MapToApi(Constants.ApiName)]
+ public class UmbracoExtensionApiControllerBase : ControllerBase
+ {
+ }
+}
diff --git a/templates/UmbracoExtension/README.txt b/templates/UmbracoExtension/README.txt
new file mode 100644
index 0000000000..7beee9137e
--- /dev/null
+++ b/templates/UmbracoExtension/README.txt
@@ -0,0 +1,38 @@
+ _ _ _
+ | | | | | |
+ __| | ___ | |_ _ __ ___| |_ _ __ _____ __
+ / _` |/ _ \| __| '_ \ / _ \ __| | '_ \ / _ \ \ /\ / /
+ | (_| | (_) | |_| | | | __/ |_ | | | | __/\ V V /
+ \__,_|\___/ \__|_| |_|\___|\__| |_| |_|\___| \_/\_/ _ _
+ | | | | (_)
+ _ _ _ __ ___ | |__ _ __ __ _ ___ ___ _____ _| |_ ___ _ __ ___ _ ___ _ __
+ | | | | '_ ` _ \| '_ \| '__/ _` |/ __/ _ \ / _ \ \/ / __/ _ \ '_ \/ __| |/ _ \| '_ \
+ | |_| | | | | | | |_) | | | (_| | (_| (_) | | __/> <| || __/ | | \__ \ | (_) | | | |
+ \__,_|_| |_| |_|_.__/|_| \__,_|\___\___/ \___/_/\_\\__\___|_| |_|___/_|\___/|_| |_|
+
+
+== Requirements ==
+* Node LTS Version 20.17.0+
+* Use a tool such as NVM (Node Version Manager) for your OS to help manage multiple versions of Node
+
+== Node Version Manager tools ==
+* https://github.com/coreybutler/nvm-windows
+* https://github.com/nvm-sh/nvm
+* https://docs.volta.sh/guide/getting-started
+
+== Steps ==
+* Open a terminal inside the `\Client` folder
+* Run `npm install` to install all the dependencies
+* Run `npm run build` to build the project
+* The build output is copied to `wwwroot\App_Plugins\UmbracoExtension\umbraco-extension.js`
+
+== File Watching ==
+* Add this Razor Class Library Project as a project reference to an Umbraco Website project
+* From the `\Client` folder run the command `npm run watch` this will monitor the changes to the *.ts files and rebuild the project
+* With the Umbraco website project running the Razor Class Library Project will refresh the browser when the build is complete
+
+== Suggestion ==
+* Use VSCode as the editor of choice as it has good tooling support for TypeScript and it will recommend a VSCode Extension for good Lit WebComponent completions
+
+== Other Resources ==
+* Umbraco Docs - https://docs.umbraco.com/umbraco-cms/customizing/extend-and-customize-editing-experience
diff --git a/templates/UmbracoPackageRcl/UmbracoPackage.csproj b/templates/UmbracoExtension/Umbraco.Extension.csproj
similarity index 50%
rename from templates/UmbracoPackageRcl/UmbracoPackage.csproj
rename to templates/UmbracoExtension/Umbraco.Extension.csproj
index b959751c87..3b70140f35 100644
--- a/templates/UmbracoPackageRcl/UmbracoPackage.csproj
+++ b/templates/UmbracoExtension/Umbraco.Extension.csproj
@@ -4,16 +4,14 @@
enable
enable
true
- UmbracoPackage
- App_Plugins/UmbracoPackage
+ Umbraco.Extension
+ /
- UmbracoPackage
- UmbracoPackage
- UmbracoPackage
- ...
- umbraco plugin package
+ Umbraco.Extension
+ Umbraco.Extension
+ Umbraco.Extension
@@ -23,5 +21,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/UmbracoPackage/.template.config/dotnetcli.host.json b/templates/UmbracoPackage/.template.config/dotnetcli.host.json
deleted file mode 100644
index 6473c5c643..0000000000
--- a/templates/UmbracoPackage/.template.config/dotnetcli.host.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/dotnetcli.host.json",
- "symbolInfo": {
- "Framework": {
- "longName": "Framework",
- "shortName": "F",
- "isHidden": true
- },
- "UmbracoVersion": {
- "longName": "version",
- "shortName": "v"
- },
- "SkipRestore": {
- "longName": "no-restore",
- "shortName": ""
- }
- }
-}
diff --git a/templates/UmbracoPackage/.template.config/ide.host.json b/templates/UmbracoPackage/.template.config/ide.host.json
deleted file mode 100644
index 0464cfeb1f..0000000000
--- a/templates/UmbracoPackage/.template.config/ide.host.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/ide.host.json",
- "order": 0,
- "icon": "../../icon.png",
- "description": {
- "id": "UmbracoPackage",
- "text": "Umbraco Package - An empty Umbraco CMS package/plugin."
- },
- "symbolInfo": [
- {
- "id": "UmbracoVersion",
- "isVisible": true
- }
- ]
-}
diff --git a/templates/UmbracoPackage/.template.config/template.json b/templates/UmbracoPackage/.template.config/template.json
deleted file mode 100644
index 5c93b1d68d..0000000000
--- a/templates/UmbracoPackage/.template.config/template.json
+++ /dev/null
@@ -1,108 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/template.json",
- "author": "Umbraco HQ",
- "classifications": [
- "Web",
- "CMS",
- "Umbraco",
- "Package",
- "Plugin"
- ],
- "name": "Umbraco Package",
- "description": "An empty Umbraco package/plugin project ready to get started.",
- "groupIdentity": "Umbraco.Templates.UmbracoPackage",
- "identity": "Umbraco.Templates.UmbracoPackage.CSharp",
- "shortName": "umbracopackage",
- "tags": {
- "language": "C#",
- "type": "project"
- },
- "sourceName": "UmbracoPackage",
- "defaultName": "UmbracoPackage1",
- "preferNameDirectory": true,
- "symbols": {
- "Framework": {
- "displayName": "Framework",
- "description": "The target framework for the project.",
- "type": "parameter",
- "datatype": "choice",
- "choices": [
- {
- "displayName": ".NET 9.0",
- "description": "Target net9.0",
- "choice": "net9.0"
- }
- ],
- "defaultValue": "net9.0",
- "replaces": "net9.0"
- },
- "UmbracoVersion": {
- "displayName": "Umbraco version",
- "description": "The version of Umbraco.Cms to add as PackageReference.",
- "type": "parameter",
- "datatype": "string",
- "defaultValue": "*",
- "replaces": "UMBRACO_VERSION_FROM_TEMPLATE"
- },
- "SkipRestore": {
- "displayName": "Skip restore",
- "description": "If specified, skips the automatic restore of the project on create.",
- "type": "parameter",
- "datatype": "bool",
- "defaultValue": "false"
- },
- "Namespace": {
- "type": "derived",
- "valueSource": "name",
- "valueTransform": "safe_namespace",
- "fileRename": "UmbracoPackage",
- "replaces": "UmbracoPackage"
- },
- "MsBuildName": {
- "type": "generated",
- "generator": "regex",
- "dataType": "string",
- "parameters": {
- "source": "name",
- "steps": [
- {
- "regex": "\\s",
- "replacement": ""
- },
- {
- "regex": "\\.",
- "replacement": ""
- },
- {
- "regex": "-",
- "replacement": ""
- },
- {
- "regex": "^[^a-zA-Z_]+",
- "replacement": ""
- }
- ]
- },
- "replaces": "UmbracoPackageMsBuild"
- }
- },
- "primaryOutputs": [
- {
- "path": "UmbracoPackage.csproj"
- }
- ],
- "postActions": [
- {
- "id": "restore",
- "condition": "(!SkipRestore)",
- "description": "Restore NuGet packages required by this project.",
- "manualInstructions": [
- {
- "text": "Run 'dotnet restore'"
- }
- ],
- "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
- "continueOnError": true
- }
- ]
-}
diff --git a/templates/UmbracoPackage/App_Plugins/UmbracoPackage/umbraco-package.json b/templates/UmbracoPackage/App_Plugins/UmbracoPackage/umbraco-package.json
deleted file mode 100644
index 153f0b0576..0000000000
--- a/templates/UmbracoPackage/App_Plugins/UmbracoPackage/umbraco-package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "id": "UmbracoPackage",
- "name": "UmbracoPackage",
- "allowPackageTelemetry": true,
- "extensions": []
-}
diff --git a/templates/UmbracoPackage/UmbracoPackage.csproj b/templates/UmbracoPackage/UmbracoPackage.csproj
deleted file mode 100644
index 9790da947c..0000000000
--- a/templates/UmbracoPackage/UmbracoPackage.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
- net9.0
- enable
- enable
- .
- UmbracoPackage
-
-
-
- UmbracoPackage
- UmbracoPackage
- UmbracoPackage
- ...
- umbraco plugin package
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets b/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets
deleted file mode 100644
index 4c376ac97b..0000000000
--- a/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
- $(MSBuildThisFileDirectory)..\App_Plugins\UmbracoPackage\**\*.*
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/templates/UmbracoPackageRcl/.template.config/ide.host.json b/templates/UmbracoPackageRcl/.template.config/ide.host.json
deleted file mode 100644
index 8e630f1e99..0000000000
--- a/templates/UmbracoPackageRcl/.template.config/ide.host.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/ide.host.json",
- "order": 0,
- "icon": "../../icon.png",
- "description": {
- "id": "UmbracoPackageRcl",
- "text": "Umbraco Package RCL - An empty Umbraco package/plugin (Razor Class Library)."
- },
- "symbolInfo": [
- {
- "id": "UmbracoVersion",
- "isVisible": true
- },
- {
- "id": "SupportPagesAndViews",
- "isVisible": true,
- "persistenceScope": "templateGroup"
- }
- ]
-}
diff --git a/templates/UmbracoPackageRcl/.template.config/template.json b/templates/UmbracoPackageRcl/.template.config/template.json
deleted file mode 100644
index c03c860141..0000000000
--- a/templates/UmbracoPackageRcl/.template.config/template.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/template.json",
- "author": "Umbraco HQ",
- "classifications": [
- "Web",
- "CMS",
- "Umbraco",
- "Package",
- "Plugin",
- "Razor Class Library"
- ],
- "name": "Umbraco Package RCL",
- "description": "An empty Umbraco package/plugin (Razor Class Library).",
- "groupIdentity": "Umbraco.Templates.UmbracoPackageRcl",
- "identity": "Umbraco.Templates.UmbracoPackageRcl.CSharp",
- "shortName": "umbracopackage-rcl",
- "tags": {
- "language": "C#",
- "type": "project"
- },
- "sourceName": "UmbracoPackage",
- "defaultName": "UmbracoPackage1",
- "preferNameDirectory": true,
- "symbols": {
- "Framework": {
- "displayName": "Framework",
- "description": "The target framework for the project.",
- "type": "parameter",
- "datatype": "choice",
- "choices": [
- {
- "displayName": ".NET 9.0",
- "description": "Target net9.0",
- "choice": "net9.0"
- }
- ],
- "defaultValue": "net9.0",
- "replaces": "net9.0"
- },
- "UmbracoVersion": {
- "displayName": "Umbraco version",
- "description": "The version of Umbraco.Cms to add as PackageReference.",
- "type": "parameter",
- "datatype": "string",
- "defaultValue": "*",
- "replaces": "UMBRACO_VERSION_FROM_TEMPLATE"
- },
- "SkipRestore": {
- "displayName": "Skip restore",
- "description": "If specified, skips the automatic restore of the project on create.",
- "type": "parameter",
- "datatype": "bool",
- "defaultValue": "false"
- },
- "SupportPagesAndViews": {
- "type": "parameter",
- "datatype": "bool",
- "defaultValue": "false",
- "displayName": "Support pages and views",
- "description": "Whether to support adding traditional Razor pages and Views to this library."
- }
- },
- "primaryOutputs": [
- {
- "path": "UmbracoPackage.csproj"
- }
- ],
- "postActions": [
- {
- "id": "restore",
- "condition": "(!SkipRestore)",
- "description": "Restore NuGet packages required by this project.",
- "manualInstructions": [
- {
- "text": "Run 'dotnet restore'"
- }
- ],
- "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
- "continueOnError": true
- }
- ]
-}
diff --git a/templates/UmbracoPackageRcl/wwwroot/umbraco-package.json b/templates/UmbracoPackageRcl/wwwroot/umbraco-package.json
deleted file mode 100644
index 153f0b0576..0000000000
--- a/templates/UmbracoPackageRcl/wwwroot/umbraco-package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "id": "UmbracoPackage",
- "name": "UmbracoPackage",
- "allowPackageTelemetry": true,
- "extensions": []
-}