Squashed commit of the following:
commit d7bdb05df56ebd7f2f3b64d2a9c71fd105ea534f
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date: Thu Jun 2 09:36:53 2022 +0200
rename event
commit 0fa096d3f1a971672e2170f199046365f433c0d0
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date: Thu Jun 2 09:34:09 2022 +0200
rename datatype event
commit ba92bdd11410b4e4beef167306e4512a75e4dc69
Author: Mads Rasmussen <madsr@hey.com>
Date: Thu Jun 2 08:49:14 2022 +0200
fix width of router slot
commit 41960b8e6ac74cd616fec5d6871710aa60f31adc
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 22:01:19 2022 +0200
clean up
commit 7dcde3153d69b05cf5560519c8cb8ca62911b777
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 21:44:50 2022 +0200
format
commit 7645687c6f81a9c83449c6396a1741d55a795b49
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 21:42:43 2022 +0200
lazy load routes
commit a439164c53ad687c2ddab83d15a79a3009f6dbfb
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 19:06:13 2022 +0200
use createExtensionElement in router
commit e851bca7fe02f14b9d60680b4de536caba924cc2
Merge: e6435d8 6779bd3
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 16:55:29 2022 +0200
Merge branch 'main' into feature/try-router-slot
commit e6435d86034ba0daa91b92dddc56c33b26e649b1
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 16:40:31 2022 +0200
remove section context
commit e0e63777069a8c4222f1fd3d0868bb68601ce929
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 16:17:39 2022 +0200
Remove unused code
commit 70c46bbfe5d26b50f449de3161f87605bd4e64d2
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 16:14:37 2022 +0200
add missing import
commit 42bf326e3ca9921d8c22e59d9c7bbda8b7954fc9
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 16:13:31 2022 +0200
wire update current state + redirects
commit 3b85abcc97481f3c3a1b9b7def85e4fd7577975e
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 15:00:44 2022 +0200
set current section
commit 78a13a217252a45bd625ff9a53071069d9906c0b
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 14:46:42 2022 +0200
remove unused router
commit 0d0ca217f5214d08d039c12fbbbb131c99c73101
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 14:43:15 2022 +0200
wire up href on tree item with router-slot
commit ea1676e8fcf9897aa632999353dd1ccd4aeca2cf
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 14:15:50 2022 +0200
setup root routing logic with router-slot
commit d3751118b0b67c5607d30ca9276b20b09381992a
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 13:56:19 2022 +0200
setup up content nodes with router-slot
commit 81875b33544b05c68197772a421d4e6ba75c5aca
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 13:45:27 2022 +0200
remove unused
commit c53ee6ee7eab6d5a21b2e5b35afd583891727599
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 13:38:25 2022 +0200
render dashboards through router-slot
commit 93fd2d7d05669c9b869c50da5d0e45ff81c4caa7
Author: Mads Rasmussen <madsr@hey.com>
Date: Wed Jun 1 13:26:42 2022 +0200
redirect after login
commit 2ea950547b4521cf21f4653c127f77effa9fba9e
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date: Wed Jun 1 12:41:06 2022 +0200
type
commit e78ab72ef8002ca49457c43998a2945c3e9587a7
Author: Niels Lyngsø <niels.lyngso@gmail.com>
Date: Wed Jun 1 11:59:40 2022 +0200
router-slot basic impl
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Umbraco</title>
|
||||
<script type="module" src="/src/index.ts"></script>
|
||||
<base href="/">
|
||||
</head>
|
||||
|
||||
<body class="uui-font uui-text" style="margin: 0; padding: 0">
|
||||
|
||||
11
src/Umbraco.Web.UI.Client/package-lock.json
generated
11
src/Umbraco.Web.UI.Client/package-lock.json
generated
@@ -13,6 +13,7 @@
|
||||
"element-internals-polyfill": "^1.1.4",
|
||||
"lit": "^2.2.5",
|
||||
"openapi-typescript-fetch": "^1.1.3",
|
||||
"router-slot": "^1.5.5",
|
||||
"rxjs": "^7.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -6337,6 +6338,11 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/router-slot": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/router-slot/-/router-slot-1.5.5.tgz",
|
||||
"integrity": "sha512-wu+6ZAaU37ARD24Jox9CWFvQ4s6PWL6LiqkqpphLLGNer+J6530HzZ64HXPDQBaCwAx82TAzUhZDvSAtaxJX2A=="
|
||||
},
|
||||
"node_modules/run-async": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||
@@ -12206,6 +12212,11 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"router-slot": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/router-slot/-/router-slot-1.5.5.tgz",
|
||||
"integrity": "sha512-wu+6ZAaU37ARD24Jox9CWFvQ4s6PWL6LiqkqpphLLGNer+J6530HzZ64HXPDQBaCwAx82TAzUhZDvSAtaxJX2A=="
|
||||
},
|
||||
"run-async": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"element-internals-polyfill": "^1.1.4",
|
||||
"lit": "^2.2.5",
|
||||
"openapi-typescript-fetch": "^1.1.3",
|
||||
"router-slot": "^1.5.5",
|
||||
"rxjs": "^7.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,61 +1,35 @@
|
||||
import './auth/auth-layout.element';
|
||||
import './auth/login/login.element';
|
||||
import './backoffice/backoffice.element';
|
||||
import './installer/installer.element';
|
||||
import './node-editor/node-editor-layout.element';
|
||||
import './node-editor/node-property-data-type.element';
|
||||
import './node-editor/node-property.element';
|
||||
import 'router-slot';
|
||||
import '@umbraco-ui/uui-css/dist/uui-css.css';
|
||||
|
||||
import { UUIIconRegistryEssential } from '@umbraco-ui/uui';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { getInitStatus } from './core/api/fetcher';
|
||||
import { UmbContextProviderMixin } from './core/context';
|
||||
import {
|
||||
isUmbRouterBeforeEnterEvent,
|
||||
UmbRoute,
|
||||
UmbRouteLocation,
|
||||
UmbRouter,
|
||||
UmbRouterBeforeEnterEvent,
|
||||
umbRouterBeforeEnterEventType,
|
||||
} from './core/router';
|
||||
import { UmbSectionContext } from './section.context';
|
||||
import { UmbNodeStore } from './core/stores/node.store';
|
||||
import { UmbDataTypeStore } from './core/stores/data-type.store';
|
||||
|
||||
// TODO: lazy load these
|
||||
const routes: Array<UmbRoute> = [
|
||||
// Load these in the correct components
|
||||
import './node-editor/node-editor-layout.element';
|
||||
import './node-editor/node-property-data-type.element';
|
||||
import './node-editor/node-property.element';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/login',
|
||||
alias: 'login',
|
||||
meta: { requiresAuth: false },
|
||||
path: 'login',
|
||||
component: () => import('./auth/login/login.element'),
|
||||
},
|
||||
{
|
||||
path: '/install',
|
||||
alias: 'install',
|
||||
meta: { requiresAuth: false },
|
||||
path: 'install',
|
||||
component: () => import('./installer/installer.element'),
|
||||
},
|
||||
{
|
||||
path: '/section/:section',
|
||||
alias: 'app',
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: '/section/:section/dashboard/:dashboard',
|
||||
alias: 'dashboard',
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: '/section/:section/node/:nodeId',
|
||||
alias: 'node',
|
||||
meta: { requiresAuth: true },
|
||||
path: '**',
|
||||
component: () => import('./backoffice/backoffice.element'),
|
||||
},
|
||||
];
|
||||
|
||||
// Import somewhere else?
|
||||
@customElement('umb-app')
|
||||
export class UmbApp extends UmbContextProviderMixin(LitElement) {
|
||||
static styles = css`
|
||||
@@ -68,106 +42,50 @@ export class UmbApp extends UmbContextProviderMixin(LitElement) {
|
||||
`;
|
||||
|
||||
private _iconRegistry: UUIIconRegistryEssential = new UUIIconRegistryEssential();
|
||||
|
||||
private _isInstalled = false;
|
||||
|
||||
private _view?: HTMLElement;
|
||||
private _router?: UmbRouter;
|
||||
private _locationSubscription?: Subscription;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.addEventListener(umbRouterBeforeEnterEventType, this._onBeforeEnter);
|
||||
this._iconRegistry.attach(this);
|
||||
|
||||
const { extensionRegistry } = window.Umbraco;
|
||||
|
||||
this.provideContext('umbExtensionRegistry', window.Umbraco.extensionRegistry);
|
||||
this.provideContext('umbSectionContext', new UmbSectionContext(extensionRegistry));
|
||||
this.provideContext('umbExtensionRegistry', extensionRegistry);
|
||||
|
||||
// TODO: consider providing somethings for install/login and some only for 'backoffice'.
|
||||
this.provideContext('umbNodeStore', new UmbNodeStore());
|
||||
this.provideContext('umbDataTypeStore', new UmbDataTypeStore());
|
||||
}
|
||||
|
||||
private _onBeforeEnter = (event: Event) => {
|
||||
if (!isUmbRouterBeforeEnterEvent(event)) return;
|
||||
this._handleUnauthorizedNavigation(event);
|
||||
};
|
||||
|
||||
private _handleUnauthorizedNavigation(event: UmbRouterBeforeEnterEvent) {
|
||||
if (event.to.route.meta.requiresAuth && !this._isAuthorized()) {
|
||||
event.preventDefault();
|
||||
this._router?.push('/login');
|
||||
}
|
||||
}
|
||||
|
||||
private _isAuthorized(): boolean {
|
||||
return sessionStorage.getItem('is-authenticated') === 'true';
|
||||
}
|
||||
|
||||
protected async firstUpdated(): Promise<void> {
|
||||
this._router = new UmbRouter(this);
|
||||
this._router.setRoutes(routes);
|
||||
this.shadowRoot?.querySelector('router-slot')?.render();
|
||||
|
||||
// TODO: find a solution for magic strings
|
||||
this.provideContext('umbRouter', this._router);
|
||||
|
||||
this._useLocation(); // TODO: Are we sure we want to do this here? The installer cannot be shown if we don't act on the routes at this point...
|
||||
|
||||
// TODO: this is a temporary routing solution for shell elements
|
||||
try {
|
||||
const { data } = await getInitStatus({});
|
||||
|
||||
this._isInstalled = data.installed;
|
||||
|
||||
if (!this._isInstalled) {
|
||||
this._router.push('/install');
|
||||
history.pushState(null, '', '/install');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isAuthorized() || window.location.pathname === '/install') {
|
||||
this._router.push('/login');
|
||||
history.pushState(null, '', 'login');
|
||||
} else {
|
||||
const next = window.location.pathname === '/' ? '/section/content' : window.location.pathname;
|
||||
this._router.push(next);
|
||||
history.pushState(null, '', next);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
private _useLocation() {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._locationSubscription = this._router?.location.subscribe((location: UmbRouteLocation) => {
|
||||
if (location.route.alias === 'login') {
|
||||
this._renderView('umb-login');
|
||||
return;
|
||||
}
|
||||
|
||||
if (location.route.alias === 'install') {
|
||||
this._renderView('umb-installer');
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderView('umb-backoffice');
|
||||
});
|
||||
}
|
||||
|
||||
_renderView(view: string) {
|
||||
if (this._view?.tagName === view.toUpperCase()) return;
|
||||
this._view = document.createElement(view);
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this._view}`;
|
||||
return html`<router-slot id="outlet" .routes=${routes}></router-slot>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,11 @@ import { customElement, state } from 'lit/decorators.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
|
||||
import { postUserLogin } from '../../core/api/fetcher';
|
||||
import { UmbContextConsumerMixin } from '../../core/context';
|
||||
import { UmbRouter } from '../../core/router';
|
||||
|
||||
// create custom element with lit-element named 'umb-login'
|
||||
import '../auth-layout.element';
|
||||
|
||||
@customElement('umb-login')
|
||||
export class UmbLogin extends UmbContextConsumerMixin(LitElement) {
|
||||
export default class UmbLogin extends LitElement {
|
||||
static styles: CSSResultGroup = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -24,18 +22,6 @@ export class UmbLogin extends UmbContextConsumerMixin(LitElement) {
|
||||
@state()
|
||||
private _loggingIn = false;
|
||||
|
||||
_router?: UmbRouter;
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// TODO: find solution for magic string
|
||||
// TODO: can we use a property decorator and a callback?
|
||||
this.consumeContext('umbRouter', (api: unknown) => {
|
||||
this._router = api as UmbRouter;
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSubmit = (e: SubmitEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -55,14 +41,12 @@ export class UmbLogin extends UmbContextConsumerMixin(LitElement) {
|
||||
};
|
||||
|
||||
private async _login(username: string, password: string, persist: boolean) {
|
||||
console.log('LOGIN', username, password, persist);
|
||||
this._loggingIn = true;
|
||||
|
||||
try {
|
||||
await postUserLogin({ username, password, persist });
|
||||
this._loggingIn = false;
|
||||
// TODO: how do we know where to go?
|
||||
this._router?.push('/section/content');
|
||||
history.pushState(null, '', '/section');
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this._loggingIn = false;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Subscription, map } from 'rxjs';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, CSSResultGroup, html, LitElement } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { isPathActive, path } from 'router-slot';
|
||||
|
||||
import { getUserSections } from '../core/api/fetcher';
|
||||
import { UmbExtensionRegistry, UmbExtensionManifest, UmbExtensionManifestSection } from '../core/extension';
|
||||
import { UmbContextConsumerMixin } from '../core/context';
|
||||
import { UmbExtensionManifestSection } from '../core/extension';
|
||||
import { UmbRouteLocation, UmbRouter } from '../core/router';
|
||||
import { UmbSectionContext } from '../section.context';
|
||||
|
||||
@customElement('umb-backoffice-header-sections')
|
||||
export class UmbBackofficeHeaderSections extends UmbContextConsumerMixin(LitElement) {
|
||||
@@ -56,24 +55,15 @@ export class UmbBackofficeHeaderSections extends UmbContextConsumerMixin(LitElem
|
||||
@state()
|
||||
private _currentSectionAlias = '';
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _sectionContext?: UmbSectionContext;
|
||||
private _extensionRegistry?: UmbExtensionRegistry;
|
||||
|
||||
private _sectionSubscription?: Subscription;
|
||||
private _currentSectionSubscription?: Subscription;
|
||||
private _locationSubscription?: Subscription;
|
||||
private _location?: UmbRouteLocation;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbRouter', (_instance: UmbRouter) => {
|
||||
this._router = _instance;
|
||||
this._useLocation();
|
||||
});
|
||||
|
||||
this.consumeContext('umbSectionContext', (_instance: UmbSectionContext) => {
|
||||
this._sectionContext = _instance;
|
||||
this._useCurrentSection();
|
||||
this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => {
|
||||
this._extensionRegistry = extensionRegistry;
|
||||
this._useSections();
|
||||
});
|
||||
}
|
||||
@@ -92,69 +82,48 @@ export class UmbBackofficeHeaderSections extends UmbContextConsumerMixin(LitElem
|
||||
}
|
||||
|
||||
// TODO: this could maybe be handled by an anchor tag
|
||||
this._router?.push(`/section/${section.meta.pathname}`);
|
||||
this._sectionContext?.setCurrent(section.alias);
|
||||
history.pushState(null, '', `/section/${section.meta.pathname}`);
|
||||
}
|
||||
|
||||
private _handleLabelClick(e: PointerEvent) {
|
||||
const label = (e.target as any).label;
|
||||
|
||||
// TODO: set current section
|
||||
//this._sectionContext?.setCurrent(section.alias);
|
||||
|
||||
private _handleLabelClick() {
|
||||
const moreTab = this.shadowRoot?.getElementById('moreTab');
|
||||
moreTab?.setAttribute('active', 'true');
|
||||
|
||||
this._open = false;
|
||||
}
|
||||
|
||||
private _useLocation() {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._locationSubscription = this._router?.location.subscribe((location: UmbRouteLocation) => {
|
||||
this._location = location;
|
||||
});
|
||||
}
|
||||
|
||||
private _useCurrentSection() {
|
||||
this._currentSectionSubscription?.unsubscribe();
|
||||
|
||||
this._currentSectionSubscription = this._sectionContext?.getCurrent().subscribe((section) => {
|
||||
this._currentSectionAlias = section.alias;
|
||||
});
|
||||
}
|
||||
|
||||
private async _useSections() {
|
||||
this._sectionSubscription?.unsubscribe();
|
||||
|
||||
const { data } = await getUserSections({});
|
||||
this._allowedSection = data.sections;
|
||||
|
||||
this._sectionSubscription = this._sectionContext?.getSections().subscribe((sectionExtensions) => {
|
||||
this._sections = sectionExtensions.filter((section) => this._allowedSection.includes(section.alias));
|
||||
this._visibleSections = this._sections;
|
||||
const currentSectionAlias = this._sections.find(
|
||||
(section) => section.meta.pathname === this._location?.params?.section
|
||||
)?.alias;
|
||||
if (!currentSectionAlias) return;
|
||||
this._sectionContext?.setCurrent(currentSectionAlias);
|
||||
});
|
||||
this._sectionSubscription = this._extensionRegistry?.extensions
|
||||
.pipe(
|
||||
map((extensions: Array<UmbExtensionManifest>) =>
|
||||
extensions
|
||||
.filter((extension) => extension.type === 'section')
|
||||
.sort((a: any, b: any) => b.meta.weight - a.meta.weight)
|
||||
)
|
||||
)
|
||||
.subscribe((sections: Array<any>) => {
|
||||
this._sections = sections.filter((section: any) => this._allowedSection.includes(section.alias));
|
||||
this._visibleSections = this._sections;
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
this._sectionSubscription?.unsubscribe();
|
||||
this._currentSectionSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-tab-group id="tabs">
|
||||
${this._visibleSections.map(
|
||||
(section) => html`
|
||||
(section: any) => html`
|
||||
<uui-tab
|
||||
?active="${this._currentSectionAlias === section.alias}"
|
||||
?active="${isPathActive(`/section/${section.meta.pathname}`, path())}"
|
||||
label="${section.name}"
|
||||
@click="${(e: PointerEvent) => this._handleTabClick(e, section)}"></uui-tab>
|
||||
`
|
||||
|
||||
@@ -4,6 +4,7 @@ import { customElement } from 'lit/decorators.js';
|
||||
|
||||
import './backoffice-header-sections.element';
|
||||
import './backoffice-header-tools.element';
|
||||
|
||||
@customElement('umb-backoffice-header')
|
||||
export class UmbBackofficeHeader extends LitElement {
|
||||
static styles: CSSResultGroup = [
|
||||
|
||||
@@ -2,11 +2,15 @@ import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { state } from 'lit/decorators.js';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Subscription, map } from 'rxjs';
|
||||
|
||||
import { UmbContextConsumerMixin } from '../core/context';
|
||||
import { UmbSectionContext } from '../section.context';
|
||||
import { UmbExtensionManifest } from '../core/extension';
|
||||
import {
|
||||
UmbExtensionRegistry,
|
||||
createExtensionElement,
|
||||
UmbExtensionManifest,
|
||||
UmbExtensionManifestSection,
|
||||
} from '../core/extension';
|
||||
|
||||
@defineElement('umb-backoffice-main')
|
||||
export class UmbBackofficeMain extends UmbContextConsumerMixin(LitElement) {
|
||||
@@ -22,52 +26,59 @@ export class UmbBackofficeMain extends UmbContextConsumerMixin(LitElement) {
|
||||
];
|
||||
|
||||
@state()
|
||||
private _sectionElement?: HTMLElement;
|
||||
private _routes: Array<any> = [];
|
||||
|
||||
private _sectionContext?: UmbSectionContext;
|
||||
private _currentSectionSubscription?: Subscription;
|
||||
@state()
|
||||
private _sections: Array<UmbExtensionManifestSection> = [];
|
||||
|
||||
private _extensionRegistry?: UmbExtensionRegistry;
|
||||
private _sectionSubscription?: Subscription;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbSectionContext', (_instance: UmbSectionContext) => {
|
||||
this._sectionContext = _instance;
|
||||
this._useCurrentSection();
|
||||
this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => {
|
||||
this._extensionRegistry = _instance;
|
||||
this._useSections();
|
||||
});
|
||||
}
|
||||
|
||||
private _useCurrentSection() {
|
||||
this._currentSectionSubscription?.unsubscribe();
|
||||
private _useSections() {
|
||||
this._sectionSubscription?.unsubscribe();
|
||||
|
||||
this._currentSectionSubscription = this._sectionContext?.getCurrent().subscribe((section) => {
|
||||
this._createSectionElement(section);
|
||||
});
|
||||
this._sectionSubscription = this._extensionRegistry?.extensions
|
||||
.pipe(
|
||||
map((extensions: Array<UmbExtensionManifest>) =>
|
||||
extensions
|
||||
.filter((extension) => extension.type === 'section')
|
||||
.sort((a: any, b: any) => b.meta.weight - a.meta.weight)
|
||||
)
|
||||
)
|
||||
.subscribe((sections) => {
|
||||
this._routes = [];
|
||||
this._sections = sections as Array<UmbExtensionManifestSection>;
|
||||
|
||||
this._routes = this._sections.map((section) => {
|
||||
return {
|
||||
path: 'section/' + section.meta.pathname,
|
||||
component: () => createExtensionElement(section),
|
||||
};
|
||||
});
|
||||
|
||||
this._routes.push({
|
||||
path: '**',
|
||||
redirectTo: 'section/' + this._sections[0].meta.pathname,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._currentSectionSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private async _createSectionElement(section: UmbExtensionManifest) {
|
||||
if (!section) return;
|
||||
|
||||
// TODO: How do we handle dynamic imports of our files?
|
||||
if (typeof section.js === 'string') {
|
||||
await import(/* @vite-ignore */ section.js);
|
||||
}
|
||||
|
||||
if (typeof section.js === 'function') {
|
||||
await section.js();
|
||||
}
|
||||
|
||||
if (section.elementName) {
|
||||
this._sectionElement = document.createElement(section.elementName);
|
||||
}
|
||||
this._sectionSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` ${this._sectionElement} `;
|
||||
return html`<router-slot .routes=${this._routes}></router-slot>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
@defineElement('umb-backoffice-sidebar')
|
||||
@customElement('umb-backoffice-sidebar')
|
||||
export class UmbBackofficeSidebar extends LitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
|
||||
@@ -7,7 +7,7 @@ import './backoffice-sidebar.element';
|
||||
import './backoffice-main.element';
|
||||
|
||||
@defineElement('umb-backoffice')
|
||||
export class UmbBackoffice extends LitElement {
|
||||
export default class UmbBackoffice extends LitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { IRoutingInfo } from 'router-slot';
|
||||
import { map, Subscription } from 'rxjs';
|
||||
|
||||
import { UmbContextConsumerMixin } from '../core/context';
|
||||
import { UmbExtensionManifestDashboard, UmbExtensionRegistry } from '../core/extension';
|
||||
import { UmbRouteLocation, UmbRouter } from '../core/router';
|
||||
import {
|
||||
UmbExtensionManifestDashboard,
|
||||
UmbExtensionManifest,
|
||||
UmbExtensionRegistry,
|
||||
createExtensionElement,
|
||||
} from '../core/extension';
|
||||
|
||||
@customElement('umb-content-dashboards')
|
||||
export class UmbContentDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
@@ -25,11 +30,7 @@ export class UmbContentDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
private _current = '';
|
||||
|
||||
@state()
|
||||
private _outlet?: HTMLElement;
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _locationSubscription?: Subscription;
|
||||
private _location?: UmbRouteLocation;
|
||||
private _routes: Array<any> = [];
|
||||
|
||||
private _extensionRegistry?: UmbExtensionRegistry;
|
||||
private _dashboardsSubscription?: Subscription;
|
||||
@@ -37,80 +38,51 @@ export class UmbContentDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbRouter', (_instance: UmbRouter) => {
|
||||
this._router = _instance;
|
||||
this._useLocation();
|
||||
});
|
||||
|
||||
this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => {
|
||||
this._extensionRegistry = _instance;
|
||||
this._useDashboards();
|
||||
});
|
||||
}
|
||||
|
||||
private _useLocation() {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._router?.location.subscribe((location: UmbRouteLocation) => {
|
||||
this._location = location;
|
||||
});
|
||||
}
|
||||
|
||||
private _useDashboards() {
|
||||
this._dashboardsSubscription?.unsubscribe();
|
||||
|
||||
this._dashboardsSubscription = this._extensionRegistry
|
||||
?.extensionsOfType('dashboard')
|
||||
.pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight)))
|
||||
.subscribe((dashboards) => {
|
||||
// TODO: What do we want to use as path?
|
||||
this._dashboards = dashboards;
|
||||
const dashboardLocation = decodeURIComponent(this._location?.params?.dashboard);
|
||||
const sectionLocation = this._location?.params?.section;
|
||||
this._dashboardsSubscription = this._extensionRegistry?.extensions
|
||||
.pipe(
|
||||
map((extensions: Array<UmbExtensionManifest>) =>
|
||||
extensions
|
||||
.filter((extension) => extension.type === 'dashboard')
|
||||
.sort((a: any, b: any) => b.meta.weight - a.meta.weight)
|
||||
)
|
||||
)
|
||||
.subscribe((dashboards: Array<UmbExtensionManifest>) => {
|
||||
this._dashboards = dashboards as Array<UmbExtensionManifestDashboard>;
|
||||
this._routes = [];
|
||||
|
||||
// TODO: Temp redirect solution
|
||||
if (dashboardLocation === 'undefined') {
|
||||
this._router?.push(`/section/${sectionLocation}/dashboard/${this._dashboards[0].meta.pathname}`);
|
||||
this._setCurrent(this._dashboards[0]);
|
||||
return;
|
||||
}
|
||||
this._routes = this._dashboards.map((dashboard) => {
|
||||
return {
|
||||
path: `${dashboard.meta.pathname}`,
|
||||
component: () => createExtensionElement(dashboard),
|
||||
setup: (element: UmbExtensionManifestDashboard, info: IRoutingInfo) => {
|
||||
this._current = info.match.route.path;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const dashboard = this._dashboards.find((dashboard) => dashboard.meta.pathname === dashboardLocation);
|
||||
|
||||
if (!dashboard) {
|
||||
this._router?.push(`/section/${sectionLocation}/dashboard/${this._dashboards[0].meta.pathname}`);
|
||||
this._setCurrent(this._dashboards[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
this._setCurrent(dashboard);
|
||||
this._routes.push({
|
||||
path: '**',
|
||||
redirectTo: this._dashboards[0].meta.pathname,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _handleTabClick(_e: PointerEvent, dashboard: UmbExtensionManifestDashboard) {
|
||||
// TODO: this could maybe be handled by an anchor tag
|
||||
const section = this._location?.params?.section;
|
||||
this._router?.push(`/section/${section}/dashboard/${dashboard.meta.pathname}`);
|
||||
this._setCurrent(dashboard);
|
||||
}
|
||||
|
||||
// TODO: Temp outlet solution
|
||||
private async _setCurrent(dashboard: UmbExtensionManifestDashboard) {
|
||||
if (typeof dashboard.js === 'function') {
|
||||
await dashboard.js();
|
||||
}
|
||||
|
||||
if (dashboard.elementName) {
|
||||
const element = document.createElement(dashboard.elementName);
|
||||
this._outlet = element;
|
||||
}
|
||||
|
||||
private _handleTabClick(e: PointerEvent, dashboard: UmbExtensionManifestDashboard) {
|
||||
history.pushState(null, '', `/section/content/dashboard/${dashboard.meta.pathname}`);
|
||||
this._current = dashboard.name;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
this._dashboardsSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
@@ -118,19 +90,21 @@ export class UmbContentDashboards extends UmbContextConsumerMixin(LitElement) {
|
||||
return html`
|
||||
<uui-tab-group id="tabs">
|
||||
${this._dashboards.map(
|
||||
(dashboard) => html`
|
||||
(dashboard: UmbExtensionManifestDashboard) => html`
|
||||
<uui-tab
|
||||
label=${dashboard.name}
|
||||
?active="${this._current === dashboard.name}"
|
||||
?active="${dashboard.meta.pathname === this._current}"
|
||||
@click="${(e: PointerEvent) => this._handleTabClick(e, dashboard)}"></uui-tab>
|
||||
`
|
||||
)}
|
||||
</uui-tab-group>
|
||||
${this._outlet}
|
||||
<router-slot .routes="${this._routes}"></router-slot>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default UmbContentDashboards;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-content-dashboards': UmbContentDashboards;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Subscription } from 'rxjs';
|
||||
import { DocumentNode } from '../mocks/data/content.data';
|
||||
|
||||
@customElement('umb-content-editor')
|
||||
class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
export class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -143,6 +143,8 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
export default UmbContentEditor;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-content-editor': UmbContentEditor;
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../core/context';
|
||||
import { UmbRouteLocation, UmbRouter } from '../core/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { IRoute, IRoutingInfo } from 'router-slot';
|
||||
|
||||
import './content-tree.element';
|
||||
import './content-dashboards.element';
|
||||
import './content-editor.element';
|
||||
|
||||
@customElement('umb-content-section')
|
||||
export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) {
|
||||
export class UmbContentSection extends LitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
:host {
|
||||
:host,
|
||||
#router-slot {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -22,54 +19,36 @@ export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsume
|
||||
`,
|
||||
];
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _locationSubscription?: Subscription;
|
||||
private _outlet?: HTMLElement;
|
||||
@state()
|
||||
private _routes: Array<IRoute> = [
|
||||
{
|
||||
path: 'dashboard',
|
||||
component: () => import('./content-dashboards.element'),
|
||||
},
|
||||
{
|
||||
path: 'node/:nodeId',
|
||||
component: () => import('./content-editor.element'),
|
||||
setup: (component: HTMLElement, info: IRoutingInfo) => {
|
||||
this._currentNodeId = info.match.params.nodeId;
|
||||
component.id = this._currentNodeId;
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: 'dashboard',
|
||||
},
|
||||
];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext('umbRouter', (_instance: UmbRouter) => {
|
||||
this._router = _instance;
|
||||
this._useLocation();
|
||||
});
|
||||
}
|
||||
|
||||
private _useLocation() {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._locationSubscription = this._router?.location.subscribe((location: UmbRouteLocation) => {
|
||||
// TODO: temp outlet solution
|
||||
const nodeId = location.params.nodeId;
|
||||
|
||||
this._outlet?.parentNode?.removeChild(this._outlet);
|
||||
|
||||
if (nodeId !== undefined) {
|
||||
const contentEditor = document.createElement('umb-content-editor');
|
||||
contentEditor.id = nodeId;
|
||||
this._outlet = contentEditor;
|
||||
this.requestUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
const dashboards = document.createElement('umb-content-dashboards');
|
||||
this._outlet = dashboards;
|
||||
this.requestUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
}
|
||||
@state()
|
||||
private _currentNodeId!: string;
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<!-- TODO: Figure out how we name layout components -->
|
||||
<umb-backoffice-sidebar>
|
||||
<umb-content-tree></umb-content-tree>
|
||||
<umb-content-tree .id="${this._currentNodeId}"></umb-content-tree>
|
||||
</umb-backoffice-sidebar>
|
||||
${this._outlet}
|
||||
<router-slot id="router-slot" .routes="${this._routes}"></router-slot>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { customElement, state, property } from 'lit/decorators.js';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { UmbContextConsumerMixin } from '../core/context';
|
||||
import { UmbRouteLocation, UmbRouter } from '../core/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { data } from '../mocks/data/content.data';
|
||||
import { UUIMenuItemElement } from '@umbraco-ui/uui';
|
||||
|
||||
@customElement('umb-content-tree')
|
||||
class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
class UmbContentTree extends LitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -18,81 +14,30 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
`,
|
||||
];
|
||||
|
||||
// simplified tree for testing
|
||||
@property()
|
||||
public id!: string;
|
||||
|
||||
// simplified tree data for testing
|
||||
@state()
|
||||
_tree: Array<any> = [];
|
||||
_tree: Array<any> = data;
|
||||
|
||||
@state()
|
||||
_section?: string;
|
||||
|
||||
@state()
|
||||
_currentNodeId?: number;
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _location?: UmbRouteLocation;
|
||||
private _locationSubscription?: Subscription;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// TODO: implement correct tree data
|
||||
this._tree = data;
|
||||
|
||||
this.consumeContext('umbRouter', (router: UmbRouter) => {
|
||||
this._router = router;
|
||||
this._useLocation();
|
||||
});
|
||||
}
|
||||
|
||||
private _useLocation() {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._locationSubscription = this._router?.location.subscribe((location) => {
|
||||
this._location = location;
|
||||
this._section = location.params.section;
|
||||
this._currentNodeId = parseInt(location.params.nodeId);
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
/* TODO: there are some problems with menu items and click events. They can happen on element inside and outside of the shadow dom
|
||||
which makes it difficult to find the right href in the router.
|
||||
It might make sense to make it possible to use your own anchor tag or button inside a label slot instead.
|
||||
This is a temp solution to get the href from the menu item and overwrite the router hijacking.
|
||||
*/
|
||||
private _handleMenuItemClick(e: PointerEvent) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const target = e.target as UUIMenuItemElement;
|
||||
if (!target) return;
|
||||
|
||||
const href = target.href;
|
||||
if (!href) return;
|
||||
|
||||
this._router?.push(href);
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<a href="${`/section/${this._section}`}">
|
||||
<a href="${'/section/content'}">
|
||||
<h3>Content</h3>
|
||||
</a>
|
||||
|
||||
<div class="nav-list">
|
||||
<!-- TODO: make menu item events bubble so we don't have to attach event listeners on every item -->
|
||||
${this._tree.map(
|
||||
(item) => html`
|
||||
<uui-menu-item
|
||||
@click="${this._handleMenuItemClick}"
|
||||
?active="${item.id === this._currentNodeId}"
|
||||
?active="${parseInt(this.id) === item.id}"
|
||||
data-id="${item.id}"
|
||||
label="${item.name}"
|
||||
href="/section/${this._section}/node/${item.id}">
|
||||
href="/section/content/node/${item.id}">
|
||||
<uui-icon slot="icon" name="${item.icon}"></uui-icon>
|
||||
</uui-menu-item>
|
||||
`
|
||||
|
||||
@@ -2,16 +2,14 @@ import { UmbExtensionManifest } from './extension.registry';
|
||||
import { loadExtension } from './load-extension.function';
|
||||
|
||||
export function createExtensionElement(manifest: UmbExtensionManifest): Promise<HTMLElement> | Promise<undefined> {
|
||||
|
||||
//TODO: Write tests for these extension options:
|
||||
return loadExtension(manifest).then((js) => {
|
||||
|
||||
if (manifest.elementName) {
|
||||
console.log('-- created by elementName', manifest.elementName);
|
||||
return document.createElement(manifest.elementName as any);
|
||||
}
|
||||
|
||||
console.log(js)
|
||||
console.log(js);
|
||||
|
||||
if (js) {
|
||||
if (js instanceof HTMLElement) {
|
||||
@@ -24,11 +22,11 @@ export function createExtensionElement(manifest: UmbExtensionManifest): Promise<
|
||||
}
|
||||
if ((js as any).default) {
|
||||
console.log('-- created by default class', (js as any).default);
|
||||
return new ((js as any).default) as HTMLElement;
|
||||
return new (js as any).default() as HTMLElement;
|
||||
}
|
||||
}
|
||||
|
||||
console.error('-- Extension did not succeed creating an element');
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from './extension.registry';
|
||||
export * from './create-extension-element.function';
|
||||
export * from './load-extension.function';
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { UmbExtensionManifest } from './extension.registry';
|
||||
|
||||
export function loadExtension(manifest: UmbExtensionManifest): Promise<object|HTMLElement> | Promise<null> {
|
||||
|
||||
export function loadExtension(manifest: UmbExtensionManifest): Promise<object | HTMLElement> | Promise<null> {
|
||||
if (typeof manifest.js === 'function') {
|
||||
return manifest.js() as Promise<object|HTMLElement>;
|
||||
return manifest.js() as Promise<object | HTMLElement>;
|
||||
}
|
||||
|
||||
// TODO: verify if this is acceptable solution.
|
||||
if (typeof manifest.js === 'string') {
|
||||
return import(/* @vite-ignore */manifest.js);
|
||||
return import(/* @vite-ignore */ manifest.js);
|
||||
/*
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
@@ -27,6 +26,6 @@ export function loadExtension(manifest: UmbExtensionManifest): Promise<object|HT
|
||||
*/
|
||||
}
|
||||
|
||||
console.log('-- Extension does not have any referenced JS')
|
||||
console.log('-- Extension does not have any referenced JS');
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ export class UmbDataTypeStore {
|
||||
id: 1244,
|
||||
key: 'dt-2',
|
||||
name: 'Textarea (DataType)',
|
||||
propertyEditorUIAlias: 'Umb.PropertyEditorUI.Textarea'
|
||||
propertyEditorUIAlias: 'Umb.PropertyEditorUI.Textarea',
|
||||
},
|
||||
{
|
||||
id: 1246,
|
||||
key: 'dt-3',
|
||||
name: 'External Test (DataType)',
|
||||
propertyEditorUIAlias: 'External.PropertyEditorUI.Test'
|
||||
}
|
||||
])
|
||||
propertyEditorUIAlias: 'External.PropertyEditorUI.Test',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
getById(id: number): Observable<DataTypeEntity | null> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
@defineElement('umb-dashboard-redirect-management')
|
||||
@customElement('umb-dashboard-redirect-management')
|
||||
export class UmbDashboardRedirectManagement extends LitElement {
|
||||
static styles = [UUITextStyles, css``];
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
@defineElement('umb-dashboard-welcome')
|
||||
@customElement('umb-dashboard-welcome')
|
||||
export class UmbDashboardWelcome extends LitElement {
|
||||
static styles = [UUITextStyles, css``];
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ const registerInternalManifests = async () => {
|
||||
group: 'common',
|
||||
},
|
||||
},
|
||||
/*
|
||||
/*
|
||||
{
|
||||
type: 'propertyEditorUI',
|
||||
alias: 'External.PropertyEditorUI.Test',
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getInstall, postInstall } from '../core/api/fetcher';
|
||||
import { PostInstallRequest, UmbracoInstaller, UmbracoPerformInstallRequest } from '../core/models';
|
||||
|
||||
@customElement('umb-installer')
|
||||
export class UmbInstaller extends LitElement {
|
||||
export default class UmbInstaller extends LitElement {
|
||||
static styles: CSSResultGroup = [css``];
|
||||
|
||||
@state()
|
||||
|
||||
@@ -53,7 +53,7 @@ export const data: Array<DocumentNode> = [
|
||||
label: 'External label 1',
|
||||
description: 'This is the a external property',
|
||||
dataTypeKey: 'dt-3',
|
||||
tempValue: 'Tex lkasdfkljdfsa 1'
|
||||
tempValue: 'Tex lkasdfkljdfsa 1',
|
||||
},
|
||||
],
|
||||
/*
|
||||
|
||||
@@ -34,7 +34,7 @@ class UmbNodePropertyDataType extends UmbContextConsumerMixin(LitElement) {
|
||||
|
||||
// TODO: make interface for UMBPropertyEditorElement
|
||||
@state()
|
||||
private _element?: {value?:string} & HTMLElement;// TODO: invent interface for propertyEditorUI.
|
||||
private _element?: { value?: string } & HTMLElement; // TODO: invent interface for propertyEditorUI.
|
||||
|
||||
@property()
|
||||
value?: string;
|
||||
@@ -93,34 +93,36 @@ class UmbNodePropertyDataType extends UmbContextConsumerMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
createExtensionElement(_propertyEditorUI)
|
||||
.then((el) => {
|
||||
const oldValue = this._element;
|
||||
this._element = el;
|
||||
|
||||
createExtensionElement(_propertyEditorUI).then(el => {
|
||||
// TODO: Set/Parse Data-Type-UI-configuration
|
||||
|
||||
const oldValue = this._element;
|
||||
this._element = el;
|
||||
|
||||
// TODO: Set/Parse Data-Type-UI-configuration
|
||||
|
||||
if(oldValue) {
|
||||
oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener);
|
||||
}
|
||||
|
||||
if(this._element) {
|
||||
this._element.addEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener);
|
||||
this._element.value = this.value;// Be aware its duplicated code
|
||||
}
|
||||
this.requestUpdate('element', oldValue);
|
||||
}).catch(() => {
|
||||
// TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.)
|
||||
});
|
||||
if (oldValue) {
|
||||
oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener);
|
||||
}
|
||||
|
||||
if (this._element) {
|
||||
this._element.addEventListener(
|
||||
'property-editor-change',
|
||||
this._onPropertyEditorChange as any as EventListener
|
||||
);
|
||||
this._element.value = this.value; // Be aware its duplicated code
|
||||
}
|
||||
this.requestUpdate('element', oldValue);
|
||||
})
|
||||
.catch(() => {
|
||||
// TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.)
|
||||
});
|
||||
}
|
||||
|
||||
private _onPropertyEditorChange = (e: CustomEvent) => {
|
||||
if (e.currentTarget === this._element) {
|
||||
this.value = this._element.value;
|
||||
//
|
||||
this.dispatchEvent(new CustomEvent('property-data-type-change', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new CustomEvent('property-data-type-value-change', { bubbles: true, composed: true }));
|
||||
}
|
||||
// make sure no event leave this scope.
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -50,7 +50,7 @@ class UmbNodeProperty extends LitElement {
|
||||
<umb-node-property-data-type
|
||||
.dataTypeKey=${this.property.dataTypeKey}
|
||||
.value=${this.value}
|
||||
@property-data-type-change=${this._onPropertyDataTypeChange}></umb-node-property-data-type>
|
||||
@property-data-type-value-change=${this._onPropertyDataTypeChange}></umb-node-property-data-type>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { firstValueFrom, map, ReplaySubject } from 'rxjs';
|
||||
|
||||
import { UmbExtensionManifestSection, UmbExtensionRegistry } from './core/extension';
|
||||
|
||||
export class UmbSectionContext {
|
||||
private _extensionRegistry!: UmbExtensionRegistry;
|
||||
|
||||
private _current = new ReplaySubject<UmbExtensionManifestSection>(1);
|
||||
public readonly current = this._current.asObservable();
|
||||
|
||||
constructor(_extensionRegistry: UmbExtensionRegistry) {
|
||||
this._extensionRegistry = _extensionRegistry;
|
||||
}
|
||||
|
||||
getSections() {
|
||||
return this._extensionRegistry
|
||||
.extensionsOfType('section')
|
||||
.pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight)));
|
||||
}
|
||||
|
||||
getCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
async setCurrent(sectionAlias: string) {
|
||||
const sections = await firstValueFrom(this.getSections());
|
||||
const matchedSection = sections.find((section) => section.alias === sectionAlias);
|
||||
if (matchedSection) {
|
||||
this._current.next(matchedSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user