get content data from mock service worker

This commit is contained in:
Mads Rasmussen
2022-05-30 20:29:39 +02:00
parent 6334bda0ea
commit 4b90f0522c
7 changed files with 209 additions and 183 deletions

View File

@@ -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;
});

View File

@@ -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 -->

View File

@@ -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>
`;
}

View File

@@ -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]);
}
}

View 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();

View File

@@ -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])
);
}),
];

View File

@@ -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,