get content data from mock service worker
This commit is contained in:
@@ -2,8 +2,9 @@ import { css, html, LitElement } from 'lit';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { UmbContextConsumerMixin } from '../core/context';
|
||||
import { DocumentNode, UmbContentService } from './content.service';
|
||||
import { UmbContentService } from './content.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { DocumentNode } from '../mocks/data/content.data';
|
||||
|
||||
@customElement('umb-content-editor')
|
||||
class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
@@ -44,12 +45,12 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
`,
|
||||
];
|
||||
|
||||
@state()
|
||||
_node?: DocumentNode;
|
||||
|
||||
@property()
|
||||
id!: string;
|
||||
|
||||
@state()
|
||||
_node?: DocumentNode;
|
||||
|
||||
private _contentService?: UmbContentService;
|
||||
private _nodeSubscription?: Subscription;
|
||||
|
||||
@@ -73,7 +74,7 @@ class UmbContentEditor extends UmbContextConsumerMixin(LitElement) {
|
||||
private _useNode() {
|
||||
this._nodeSubscription?.unsubscribe();
|
||||
|
||||
this._nodeSubscription = this._contentService?.getById(this.id).subscribe(node => {
|
||||
this._nodeSubscription = this._contentService?.getById(parseInt(this.id)).subscribe(node => {
|
||||
if (!node) return;
|
||||
this._node = node;
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { customElement } from 'lit/decorators.js';
|
||||
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../core/context';
|
||||
import { UmbRouteLocation, UmbRouter } from '../core/router';
|
||||
import { UmbContentService } from './content.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import './content-tree.element';
|
||||
import './content-dashboards.element';
|
||||
@@ -23,6 +24,7 @@ export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsume
|
||||
];
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _locationSubscription?: Subscription;
|
||||
private _outlet?: HTMLElement;
|
||||
|
||||
constructor () {
|
||||
@@ -36,8 +38,10 @@ export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsume
|
||||
});
|
||||
}
|
||||
|
||||
private _useLocation () {
|
||||
this._router?.location
|
||||
private _useLocation () {
|
||||
this._locationSubscription?.unsubscribe();
|
||||
|
||||
this._locationSubscription = this._router?.location
|
||||
.subscribe((location: UmbRouteLocation) => {
|
||||
// TODO: temp outlet solution
|
||||
const nodeId = location.params.nodeId;
|
||||
@@ -56,6 +60,11 @@ export class UmbContentSection extends UmbContextProviderMixin(UmbContextConsume
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<!-- TODO: Figure out how we name layout components -->
|
||||
|
||||
@@ -4,8 +4,8 @@ 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';
|
||||
import { data } from './content.service';
|
||||
|
||||
@customElement('umb-content-tree')
|
||||
class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
@@ -27,7 +27,7 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
_section?: string;
|
||||
|
||||
@state()
|
||||
_currentNodeId?: string;
|
||||
_currentNodeId?: number;
|
||||
|
||||
private _router?: UmbRouter;
|
||||
private _location?: UmbRouteLocation;
|
||||
@@ -51,10 +51,15 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
this._locationSubscription = this._router?.location.subscribe(location => {
|
||||
this._location = location;
|
||||
this._section = location.params.section;
|
||||
this._currentNodeId = location.params.nodeId;
|
||||
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.
|
||||
@@ -62,6 +67,8 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
*/
|
||||
private _handleMenuItemClick (e: PointerEvent) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const target = e.target as UUIMenuItemElement;
|
||||
if (!target) return;
|
||||
|
||||
@@ -71,11 +78,6 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
this._router?.push(href);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this._locationSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
render () {
|
||||
return html`
|
||||
<a href="${`/section/${this._section}`}">
|
||||
@@ -86,54 +88,14 @@ class UmbContentTree extends UmbContextConsumerMixin(LitElement) {
|
||||
<!-- 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
|
||||
?active="${item.id === this._currentNodeId}"
|
||||
@click="${this._handleMenuItemClick}"
|
||||
?active="${item.id === this._currentNodeId}"
|
||||
data-id="${item.id}"
|
||||
label="${item.name}"
|
||||
href="/section/${this._section}/node/${item.id}">
|
||||
<uui-icon slot="icon" name="${item.icon}"></uui-icon>
|
||||
</uui-menu-item>
|
||||
`)}
|
||||
|
||||
<!--
|
||||
<uui-menu-item label="Hello World">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Home" active has-children show-children>
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
<uui-menu-item label="Products">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="People">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="About Us" disabled has-children>
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
<uui-menu-item label="History">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Team">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="MyMenuItem" selected has-children>
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
<uui-menu-item label="History">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Team">
|
||||
<uui-icon slot="icon" name="document"></uui-icon>
|
||||
</uui-menu-item>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Blog">
|
||||
<uui-icon slot="icon" name="calendar"></uui-icon>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Contact"></uui-menu-item>
|
||||
</uui-menu-item>
|
||||
<uui-menu-item label="Recycle Bin">
|
||||
<uui-icon slot="icon" name="delete"></uui-icon>
|
||||
</uui-menu-item>
|
||||
-->
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,138 +1,37 @@
|
||||
import { BehaviorSubject, map, Observable } from 'rxjs';
|
||||
|
||||
export interface DocumentNode {
|
||||
id: string;
|
||||
key: string;
|
||||
name: string;
|
||||
alias: string;
|
||||
icon: string; // TODO: should come from the doc type?
|
||||
properties: NodeProperty[];
|
||||
data: any; // TODO: define data type
|
||||
layout?: any; // TODO: define layout type - make it non-optional
|
||||
}
|
||||
|
||||
export interface NodeProperty {
|
||||
alias: string;
|
||||
label: string;
|
||||
description: string;
|
||||
dataTypeAlias: string;
|
||||
tempValue: string; // TODO: remove this - only used for testing
|
||||
}
|
||||
|
||||
export const data: Array<DocumentNode> = [
|
||||
{
|
||||
id: '1',
|
||||
key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
|
||||
name: 'Document 1',
|
||||
alias: 'document1',
|
||||
icon: 'document',
|
||||
properties: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
label: 'Textarea label',
|
||||
description: 'this is a textarea property',
|
||||
dataTypeAlias: 'myTextStringEditor',
|
||||
tempValue: 'hello world 1'
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
label: 'Text string label',
|
||||
description: 'This is the a text string property',
|
||||
dataTypeAlias: 'myTextAreaEditor',
|
||||
tempValue: 'Tex areaaaa 1'
|
||||
},
|
||||
],
|
||||
data: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
value: 'hello world',
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
value: 'Teeeeexxxt areaaaaaa',
|
||||
},
|
||||
],
|
||||
/*
|
||||
layout: [
|
||||
{
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myHeadline'
|
||||
},
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myDescription'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
*/
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
|
||||
name: 'Document 2',
|
||||
alias: 'document2',
|
||||
icon: 'favorite',
|
||||
properties: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
label: 'Textarea label',
|
||||
description: 'this is a textarea property',
|
||||
dataTypeAlias: 'myTextStringEditor',
|
||||
tempValue: 'hello world 2'
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
label: 'Text string label',
|
||||
description: 'This is the a text string property',
|
||||
dataTypeAlias: 'myTextAreaEditor',
|
||||
tempValue: 'Tex areaaaa 2'
|
||||
},
|
||||
],
|
||||
data: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
value: 'hello world',
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
value: 'Teeeeexxxt areaaaaaa',
|
||||
},
|
||||
],
|
||||
/*
|
||||
layout: [
|
||||
{
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myHeadline'
|
||||
},
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myDescription'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
*/
|
||||
}
|
||||
];
|
||||
import { DocumentNode } from '../mocks/data/content.data';
|
||||
|
||||
export class UmbContentService {
|
||||
|
||||
private _nodes: BehaviorSubject<Array<DocumentNode>> = new BehaviorSubject(<Array<DocumentNode>>[]);
|
||||
public readonly nodes: Observable<Array<DocumentNode>> = this._nodes.asObservable();
|
||||
|
||||
constructor () {
|
||||
this._nodes.next(data);
|
||||
}
|
||||
getById (id: number): Observable<DocumentNode | null> {
|
||||
// fetch from server and update store
|
||||
fetch(`/umbraco/backoffice/content/${id}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
this._updateStore(data);
|
||||
});
|
||||
|
||||
getById (id: string): Observable<DocumentNode | null> {
|
||||
return this.nodes.pipe(map(((nodes: Array<DocumentNode>) => nodes.find((node: DocumentNode) => node.id === id) || null)));
|
||||
}
|
||||
|
||||
_updateStore (fetchedNodes: Array<any>) {
|
||||
const storedNodes = this._nodes.getValue();
|
||||
let updated: any = [...storedNodes];
|
||||
|
||||
fetchedNodes.forEach(fetchedNode => {
|
||||
const index = storedNodes.map(storedNode => storedNode.id).indexOf(fetchedNode.id);
|
||||
|
||||
if (index !== -1) {
|
||||
// If the node is already in the store, update it
|
||||
updated[index] = fetchedNode;
|
||||
} else {
|
||||
// If the node is not in the store, add it
|
||||
updated = [...updated, fetchedNode];
|
||||
}
|
||||
})
|
||||
|
||||
this._nodes.next([...updated]);
|
||||
}
|
||||
}
|
||||
136
src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts
Normal file
136
src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
export interface DocumentNode {
|
||||
id: number;
|
||||
key: string;
|
||||
name: string;
|
||||
alias: string;
|
||||
icon: string; // TODO: should come from the doc type?
|
||||
properties: NodeProperty[];
|
||||
data: any; // TODO: define data type
|
||||
layout?: any; // TODO: define layout type - make it non-optional
|
||||
}
|
||||
|
||||
export interface NodeProperty {
|
||||
alias: string;
|
||||
label: string;
|
||||
description: string;
|
||||
dataTypeAlias: string;
|
||||
tempValue: string; // TODO: remove this - only used for testing
|
||||
}
|
||||
|
||||
export const data = [
|
||||
{
|
||||
id: 1,
|
||||
key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
|
||||
name: 'Document 1',
|
||||
alias: 'document1',
|
||||
icon: 'document',
|
||||
properties: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
label: 'Textarea label',
|
||||
description: 'this is a textarea property',
|
||||
dataTypeAlias: 'myTextStringEditor',
|
||||
tempValue: 'hello world 1'
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
label: 'Text string label',
|
||||
description: 'This is the a text string property',
|
||||
dataTypeAlias: 'myTextAreaEditor',
|
||||
tempValue: 'Tex areaaaa 1'
|
||||
},
|
||||
],
|
||||
data: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
value: 'hello world',
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
value: 'Teeeeexxxt areaaaaaa',
|
||||
},
|
||||
],
|
||||
/*
|
||||
layout: [
|
||||
{
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myHeadline'
|
||||
},
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myDescription'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
*/
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
key: '74e4008a-ea4f-4793-b924-15e02fd380d3',
|
||||
name: 'Document 2',
|
||||
alias: 'document2',
|
||||
icon: 'favorite',
|
||||
properties: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
label: 'Textarea label',
|
||||
description: 'this is a textarea property',
|
||||
dataTypeAlias: 'myTextStringEditor',
|
||||
tempValue: 'hello world 2'
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
label: 'Text string label',
|
||||
description: 'This is the a text string property',
|
||||
dataTypeAlias: 'myTextAreaEditor',
|
||||
tempValue: 'Tex areaaaa 2'
|
||||
},
|
||||
],
|
||||
data: [
|
||||
{
|
||||
alias: 'myHeadline',
|
||||
value: 'hello world',
|
||||
},
|
||||
{
|
||||
alias: 'myDescription',
|
||||
value: 'Teeeeexxxt areaaaaaa',
|
||||
},
|
||||
],
|
||||
/*
|
||||
layout: [
|
||||
{
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myHeadline'
|
||||
},
|
||||
{
|
||||
type: 'property',
|
||||
alias: 'myDescription'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
*/
|
||||
}
|
||||
];
|
||||
|
||||
// Temp mocked database
|
||||
class UmbContentData {
|
||||
private _data: Array<DocumentNode> = [];
|
||||
|
||||
constructor () {
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
getById (id: number) {
|
||||
return this._data.find(item => item.id === id);
|
||||
}
|
||||
}
|
||||
|
||||
export const umbContentData = new UmbContentData();
|
||||
@@ -0,0 +1,17 @@
|
||||
import { rest } from 'msw';
|
||||
import { umbContentData } from '../data/content.data';
|
||||
|
||||
// TODO: add schema
|
||||
export const handlers = [
|
||||
rest.get('/umbraco/backoffice/content/:id', (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
|
||||
const int = parseInt(id);
|
||||
const document = umbContentData.getById(int);
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json([document])
|
||||
);
|
||||
}),
|
||||
];
|
||||
@@ -1,5 +1,6 @@
|
||||
import { rest } from 'msw';
|
||||
import { InitResponse } from '../models';
|
||||
import { handlers as contentHandlers } from './domains/content.handlers';
|
||||
import { handlers as installHandlers } from './domains/install.handlers';
|
||||
import { handlers as manifestsHandlers } from './domains/manifests.handlers';
|
||||
import { handlers as userHandlers } from './domains/user.handlers';
|
||||
@@ -15,6 +16,7 @@ export const handlers = [
|
||||
})
|
||||
);
|
||||
}),
|
||||
...contentHandlers,
|
||||
...installHandlers,
|
||||
...manifestsHandlers,
|
||||
...userHandlers,
|
||||
|
||||
Reference in New Issue
Block a user