diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-data-type-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-data-type-edit.element.ts
new file mode 100644
index 0000000000..f2ddc6c8c4
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-data-type-edit.element.ts
@@ -0,0 +1,24 @@
+import { css, html, LitElement } from 'lit';
+import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
+import { customElement, property } from 'lit/decorators.js';
+import { DataTypeEntity } from '../../mocks/data/content.data';
+
+@customElement('umb-editor-view-data-type-edit')
+export class UmbEditorViewDataTypeEditElement extends LitElement {
+ static styles = [UUITextStyles, css``];
+
+ @property({ type: Object })
+ dataType?: DataTypeEntity;
+
+ render() {
+ return html`
EDIT DATA TYPE: ${this.dataType?.id}
`;
+ }
+}
+
+export default UmbEditorViewDataTypeEditElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-editor-view-data-type-edit': UmbEditorViewDataTypeEditElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-data-type.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-data-type.element.ts
index 7c2bd3aead..f624e9348f 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-data-type.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-data-type.element.ts
@@ -1,11 +1,158 @@
-import { html, LitElement } from 'lit';
-import { customElement, property } from 'lit/decorators.js';
+import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
+import { css, html, LitElement } from 'lit';
+import { customElement, property, state } from 'lit/decorators.js';
+import { IRoute, IRoutingInfo, RouterSlot } from 'router-slot';
+import { map, Subscription } from 'rxjs';
+import { UmbContextConsumerMixin } from '../../core/context';
+import { UmbExtensionManifest, UmbExtensionManifestEditorView, UmbExtensionRegistry } from '../../core/extension';
+import { UmbDataTypeStore } from '../../core/stores/data-type.store';
+import { DataTypeEntity } from '../../mocks/data/content.data';
+
+// Lazy load
+// TODO: Make this dynamic, use load-extensions method to loop over extensions for this node.
+import '../editor-views/editor-view-data-type-edit.element';
@customElement('umb-editor-data-type')
-export class UmbEditorDataTypeElement extends LitElement {
+export class UmbEditorDataTypeElement extends UmbContextConsumerMixin(LitElement) {
+ static styles = [
+ UUITextStyles,
+ css`
+ :host {
+ display: block;
+ width: 100%;
+ height: 100%;
+ }
+
+ uui-input {
+ width: 100%;
+ margin-left: 16px;
+ }
+
+ uui-tab-group {
+ --uui-tab-divider: var(--uui-color-border);
+ border-left: 1px solid var(--uui-color-border);
+ flex-wrap: nowrap;
+ height: 60px;
+ }
+
+ uui-tab {
+ font-size: 0.8rem;
+ }
+ `,
+ ];
+
@property()
id!: string;
+ @state()
+ _dataType!: DataTypeEntity;
+
+ @state()
+ private _editorViews: Array = [];
+
+ @state()
+ private _currentView = '';
+
+ @state()
+ private _routes: Array = [];
+
+ private _dataTypeStore?: UmbDataTypeStore;
+ private _dataTypeSubscription?: Subscription;
+ private _extensionRegistry?: UmbExtensionRegistry;
+ private _editorViewsSubscription?: Subscription;
+
+ private _routerFolder = '';
+
+ constructor() {
+ super();
+
+ this.consumeContext('umbDataTypeStore', (store: UmbDataTypeStore) => {
+ this._dataTypeStore = store;
+ this._useDataType();
+ });
+
+ this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => {
+ this._extensionRegistry = extensionRegistry;
+ this._useEditorViews();
+ });
+ }
+
+ connectedCallback(): void {
+ super.connectedCallback();
+ /* TODO: find a way to construct absolute urls */
+ this._routerFolder = window.location.pathname.split('/view')[0];
+ }
+
+ private _useDataType() {
+ this._dataTypeSubscription?.unsubscribe();
+
+ this._dataTypeSubscription = this._dataTypeStore?.getById(parseInt(this.id)).subscribe((dataType) => {
+ if (!dataType) return; // TODO: Handle nicely if there is no node.
+ this._dataType = dataType;
+ // TODO: merge observables
+ this._createRoutes();
+ });
+ }
+
+ // TODO: simplify setting up editors with views. This code has to be duplicated in each editor.
+ private _useEditorViews() {
+ this._editorViewsSubscription?.unsubscribe();
+
+ // TODO: how do we know which editor to show the views for?
+ this._editorViewsSubscription = this._extensionRegistry
+ ?.extensionsOfType('editorView')
+ .pipe(
+ map((extensions) =>
+ extensions
+ .filter((extension) => extension.meta.editors.includes('Umb.Editor.DataType'))
+ .sort((a, b) => b.meta.weight - a.meta.weight)
+ )
+ )
+ .subscribe((editorViews) => {
+ this._editorViews = editorViews;
+ // TODO: merge observables
+ this._createRoutes();
+ });
+ }
+
+ private async _createRoutes() {
+ if (this._dataType && this._editorViews.length > 0) {
+ this._routes = [];
+
+ this._routes = this._editorViews.map((view) => {
+ return {
+ path: `view/${view.meta.pathname}`,
+ component: () => document.createElement(view.elementName),
+ setup: (element: HTMLElement, info: IRoutingInfo) => {
+ // TODO: make interface for EditorViews
+ const editorView = element as any;
+ // TODO: how do we pass data to views? Maybe we should use a context?
+ editorView.dataType = this._dataType;
+ this._currentView = info.match.route.path;
+ },
+ };
+ });
+
+ this._routes.push({
+ path: '**',
+ redirectTo: `view/${this._editorViews?.[0].meta.pathname}`,
+ });
+
+ this.requestUpdate();
+ await this.updateComplete;
+
+ this._forceRouteRender();
+ }
+ }
+
+ // TODO: Fgure out why this has been necessary for this case. Come up with another case
+ private _forceRouteRender() {
+ const routerSlotEl = this.shadowRoot?.querySelector('router-slot') as RouterSlot;
+ if (routerSlotEl) {
+ routerSlotEl.render();
+ }
+ }
+
private _onSave() {
console.log('SAVE DATA TYPE');
}
@@ -13,9 +160,23 @@ export class UmbEditorDataTypeElement extends LitElement {
render() {
return html`
-
+
- Some Content Here: ${this.id}
+
+ ${this._editorViews.map(
+ (view: UmbExtensionManifestEditorView) => html`
+
+
+ ${view.name}
+
+ `
+ )}
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-node.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-node.element.ts
index 8865852d53..505cb8a221 100644
--- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-node.element.ts
+++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/editor-node.element.ts
@@ -133,16 +133,17 @@ export class UmbEditorNodeElement extends UmbContextConsumerMixin(LitElement) {
this._editorViewsSubscription?.unsubscribe();
// TODO: how do we know which editor to show the views for?
- this._editorViewsSubscription = this._extensionRegistry?.extensions
+ this._editorViewsSubscription = this._extensionRegistry
+ ?.extensionsOfType('editorView')
.pipe(
- map((extensions: Array
) =>
+ map((extensions) =>
extensions
- .filter((extension) => extension.type === 'editorView')
- .sort((a: any, b: any) => b.meta.weight - a.meta.weight)
+ .filter((extension) => extension.meta.editors.includes('Umb.Editor.Node'))
+ .sort((a, b) => b.meta.weight - a.meta.weight)
)
)
- .subscribe((dashboards: Array) => {
- this._editorViews = dashboards as Array;
+ .subscribe((editorViews) => {
+ this._editorViews = editorViews;
// TODO: merge observables
this._createRoutes();
});
@@ -165,6 +166,7 @@ export class UmbEditorNodeElement extends UmbContextConsumerMixin(LitElement) {
this._onSave();
}
+ // TODO: simplify setting up editors with views. This code has to be duplicated in each editor.
private async _createRoutes() {
if (this._node && this._editorViews.length > 0) {
this._routes = [];
diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts
index 7bece422e0..9ebd68541e 100644
--- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts
+++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts
@@ -40,12 +40,12 @@ export type UmbExtensionManifestPropertyEditor = {
// Property Actions
export type UmbExtensionManifestPropertyAction = {
- type: 'propertyAction';
- meta: UmbManifestPropertyActionMeta;
+ type: 'propertyAction';
+ meta: UmbManifestPropertyActionMeta;
} & UmbExtensionManifestBase;
export type UmbManifestPropertyActionMeta = {
- propertyEditors: Array;
+ propertyEditors: Array;
};
// Dashboard:
@@ -61,6 +61,7 @@ export type UmbExtensionManifestDashboard = {
// Editor View:
export type UmbManifestEditorViewMeta = {
+ editors: Array; // TODO: how to we want to filter views?
pathname: string; // TODO: how to we want to support pretty urls?
icon: string;
weight: number;
@@ -114,6 +115,7 @@ export class UmbExtensionRegistry {
// Typings concept, need to put all core types to get a good array return type for the provided type...
extensionsOfType(type: 'section'): Observable>;
extensionsOfType(type: 'dashboard'): Observable>;
+ extensionsOfType(type: 'editorView'): Observable>;
extensionsOfType(type: 'propertyEditor'): Observable>;
extensionsOfType(type: 'propertyAction'): Observable>;
extensionsOfType(type: UmbExtensionManifestCoreTypes): Observable>;
diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts
index bc65d8dff3..fe2760f555 100644
--- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts
+++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts
@@ -95,6 +95,9 @@ export const internalManifests: Array = [
elementName: 'umb-editor-view-node-edit',
js: () => import('./backoffice/editor-views/editor-view-node-edit.element'),
meta: {
+ // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin
+ // this is a temp solution
+ editors: ['Umb.Editor.Node'],
pathname: 'content',
weight: 100,
icon: 'document',
@@ -107,11 +110,29 @@ export const internalManifests: Array = [
elementName: 'umb-editor-view-node-info',
js: () => import('./backoffice/editor-views/editor-view-node-info.element'),
meta: {
+ // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin
+ // this is a temp solution
+ editors: ['Umb.Editor.Node'],
pathname: 'info',
weight: 90,
icon: 'info',
},
},
+ {
+ type: 'editorView',
+ alias: 'Umb.EditorView.DataTypeEdit',
+ name: 'Edit',
+ elementName: 'umb-editor-view-data-type-edit',
+ js: () => import('./backoffice/editor-views/editor-view-data-type-edit.element'),
+ meta: {
+ // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin
+ // this is a temp solution
+ editors: ['Umb.Editor.DataType'],
+ pathname: 'edit',
+ weight: 90,
+ icon: 'edit',
+ },
+ },
{
type: 'propertyAction',
alias: 'Umb.PropertyAction.Copy',