fetch media items

This commit is contained in:
Mads Rasmussen
2022-12-12 13:29:55 +01:00
parent 4c66d0926a
commit 4de39ce513
8 changed files with 131 additions and 26 deletions

View File

@@ -3,11 +3,13 @@ import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import type { ManifestEditorView, ManifestWithLoader } from '@umbraco-cms/models';
import { umbExtensionsRegistry } from '@umbraco-cms/extensions-registry';
import { UmbMediaStore } from 'src/core/stores/media/media.store';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import '../shared/editor-content/editor-content.element';
@customElement('umb-editor-media')
export class UmbEditorMediaElement extends LitElement {
export class UmbEditorMediaElement extends UmbContextConsumerMixin(UmbContextProviderMixin(LitElement)) {
static styles = [
UUITextStyles,
css`
@@ -26,6 +28,10 @@ export class UmbEditorMediaElement extends LitElement {
super();
this._registerEditorViews();
this.consumeContext('umbMediaStore', (mediaStore: UmbMediaStore) => {
this.provideContext('umbContentStore', mediaStore);
});
}
private _registerEditorViews() {

View File

@@ -17,6 +17,8 @@ import '../editor-entity-layout/editor-entity-layout.element';
// TODO: Make this dynamic, use load-extensions method to loop over extensions for this node.
import './views/edit/editor-view-content-edit.element';
import './views/info/editor-view-content-info.element';
import { UmbDocumentStore } from 'src/core/stores/document/document.store';
import { UmbMediaStore } from 'src/core/stores/media/media.store';
@customElement('umb-editor-content')
export class UmbEditorContentElement extends UmbContextProviderMixin(
@@ -60,19 +62,19 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
alias!: string;
@state()
_node?: NodeEntity;
_content?: NodeEntity;
private _nodeStore?: UmbNodeStore;
private _store?: UmbDocumentStore | UmbMediaStore;
private _nodeContext?: UmbNodeContext;
private _notificationService?: UmbNotificationService;
constructor() {
super();
this.consumeAllContexts(['umbNodeStore', 'umbNotificationService'], (instances) => {
this._nodeStore = instances['umbNodeStore'];
this.consumeAllContexts(['umbContentStore', 'umbNotificationService'], (instances) => {
this._store = instances['umbContentStore'];
this._notificationService = instances['umbNotificationService'];
this._useNode();
this._observeContent();
});
this.addEventListener('property-value-change', this._onPropertyValueChange);
@@ -82,7 +84,7 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
const target = e.composedPath()[0] as any;
// TODO: Set value.
const property = this._node?.properties.find((x) => x.alias === target.alias);
const property = this._content?.properties.find((x) => x.alias === target.alias);
if (property) {
this._setPropertyValue(property.alias, target.value);
} else {
@@ -91,28 +93,29 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
};
private _setPropertyValue(alias: string, value: unknown) {
this._node?.data.forEach((data) => {
this._content?.data.forEach((data) => {
if (data.alias === alias) {
data.value = value;
}
});
}
private _useNode() {
if (!this._nodeStore) return;
private _observeContent() {
if (!this._store) return;
this.observe<NodeEntity>(this._nodeStore.getByKey(this.entityKey), (node) => {
if (!node) return; // TODO: Handle nicely if there is no node.
this.observe<NodeEntity>(this._store.getByKey(this.entityKey), (content) => {
debugger
if (!content) return; // TODO: Handle nicely if there is no node.
if (!this._nodeContext) {
this._nodeContext = new UmbNodeContext(node);
this._nodeContext = new UmbNodeContext(content);
this.provideContext('umbNodeContext', this._nodeContext);
} else {
this._nodeContext.update(node);
this._nodeContext.update(content);
}
this.observe<NodeEntity>(this._nodeContext.data.pipe(distinctUntilChanged()), (data) => {
this._node = data;
this._content = data;
});
});
}
@@ -122,9 +125,9 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
}
private _onSave() {
// TODO: What if store is not present, what if node is not loaded....
if (this._node) {
this._nodeStore?.save([this._node]).then(() => {
// TODO: What if store is not present, what if content is not loaded....
if (this._content) {
this._store?.save([this._content]).then(() => {
const data: UmbNotificationDefaultData = { message: 'Document Saved' };
this._notificationService?.peek('positive', { data });
});
@@ -161,9 +164,9 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
return html`
<umb-editor-entity-layout alias=${this.alias}>
<div slot="name">
<uui-input .value=${this._node?.name} @input="${this._handleInput}">
<uui-input .value=${this._content?.name} @input="${this._handleInput}">
<!-- Implement Variant Selector -->
${this._node && this._node.variants.length > 0
${this._content && this._content.variants.length > 0
? html`
<div slot="append">
<uui-button id="trigger" @click=${this._toggleVariantSelector}>
@@ -176,7 +179,7 @@ export class UmbEditorContentElement extends UmbContextProviderMixin(
</uui-input>
<!-- Implement Variant Selector -->
${this._node && this._node.variants.length > 0
${this._content && this._content.variants.length > 0
? html`
<uui-popover id="popover" .open=${this._variantSelectorIsOpen} @close=${this._close}>
<div id="dropdown" slot="popover">

View File

@@ -2,6 +2,7 @@ import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { UmbTreeBase } from '../shared/tree-base.element';
import { UmbContextConsumerMixin, UmbContextProviderMixin } from '@umbraco-cms/context-api';
import { UmbMediaStore } from 'src/core/stores/media/media.store';
import '../shared/tree-navigator.element';

View File

@@ -16,6 +16,7 @@ import { handlers as modelsBuilderHandlers } from './domains/modelsbuilder.handl
import { handlers as profilingHandlers } from './domains/performance-profiling.handlers';
import { handlers as documentHandlers } from './domains/document.handlers';
import { handlers as mediaHandlers } from './domains/media.handlers';
// treeHandlers
import { handlers as treeDocumentHandlers } from './domains/tree-document.handlers';
@@ -33,6 +34,7 @@ const handlers = [
...upgradeHandlers,
...userHandlers,
...documentHandlers,
...mediaHandlers,
...dataTypeHandlers,
...documentTypeHandlers,
...treeHandlers,

View File

@@ -1,6 +1,7 @@
import { UmbData } from './data';
import { ContentTreeItem, PagedContentTreeItem } from '@umbraco-cms/backend-api';
import type { MediaDetails } from '@umbraco-cms/models';
import { UmbEntityData } from './entity.data';
export const data: Array<MediaDetails> = [
{
@@ -12,6 +13,7 @@ export const data: Array<MediaDetails> = [
isContainer: false,
parentKey: null,
noAccess: false,
isTrashed: false,
properties: [
{
alias: 'myMediaHeadline',
@@ -37,6 +39,7 @@ export const data: Array<MediaDetails> = [
isContainer: false,
parentKey: null,
noAccess: false,
isTrashed: false,
properties: [
{
alias: 'myMediaDescription',
@@ -56,7 +59,7 @@ export const data: Array<MediaDetails> = [
];
// Temp mocked database
class UmbMediaData extends UmbData<MediaDetails> {
class UmbMediaData extends UmbEntityData<MediaDetails> {
constructor() {
super(data);
}

View File

@@ -0,0 +1,35 @@
import { rest } from 'msw';
import { umbMediaData } from '../data/media.data';
import type { MediaDetails } from '@umbraco-cms/models';
// TODO: add schema
export const handlers = [
rest.get('/umbraco/management/api/v1/media/details/:key', (req, res, ctx) => {
console.warn('Please move to schema');
const key = req.params.key as string;
if (!key) return;
const media = umbMediaData.getByKey(key);
return res(ctx.status(200), ctx.json([media]));
}),
rest.post<MediaDetails[]>('/umbraco/management/api/v1/media/save', async (req, res, ctx) => {
console.warn('Please move to schema');
const data = await req.json();
if (!data) return;
const saved = umbMediaData.save(data);
return res(ctx.status(200), ctx.json(saved));
}),
rest.post<string[]>('/umbraco/management/api/v1/media/trash', async (req, res, ctx) => {
console.warn('Please move to schema');
const keys = await req.json();
const trashed = umbMediaData.trash(keys);
return res(ctx.status(200), ctx.json(trashed));
}),
];

View File

@@ -10,6 +10,59 @@ import { ApiError, ContentTreeItem, MediaResource, ProblemDetails } from '@umbra
* @description - Data Store for Media
*/
export class UmbMediaStore extends UmbDataStoreBase<MediaDetails | ContentTreeItem> {
getByKey(key: string): Observable<MediaDetails | null> {
// fetch from server and update store
fetch(`/umbraco/management/api/v1/media/details/${key}`)
.then((res) => res.json())
.then((data) => {
this.update(data);
});
return this.items.pipe(map((media) => media.find((media) => media.key === key) || null));
}
// TODO: make sure UI somehow can follow the status of this action.
save(data: MediaDetails[]): Promise<void> {
// fetch from server and update store
// TODO: use Fetcher API.
let body: string;
try {
body = JSON.stringify(data);
} catch (error) {
console.error(error);
return Promise.reject();
}
// TODO: Use node type to hit the right API, or have a general Node API?
return fetch('/umbraco/management/api/v1/media/save', {
method: 'POST',
body: body,
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => res.json())
.then((data: Array<MediaDetails>) => {
this.update(data);
});
}
// TODO: how do we handle trashed items?
async trash(keys: Array<string>) {
// fetch from server and update store
// TODO: Use node type to hit the right API, or have a general Node API?
const res = await fetch('/umbraco/management/api/v1/media/trash', {
method: 'POST',
body: JSON.stringify(keys),
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json();
this.update(data);
}
getTreeRoot(): Observable<Array<ContentTreeItem>> {
MediaResource.getTreeMediaRoot({}).then(
(res) => {
@@ -24,8 +77,9 @@ export class UmbMediaStore extends UmbDataStoreBase<MediaDetails | ContentTreeIt
}
}
);
return this.items.pipe(map((items) => items.filter((item) => item.parentKey === null)));
// TODO: how do we handle trashed items?
return this.items.pipe(map((items) => items.filter((item) => item.parentKey === null && item.isTrashed === false)));
}
getTreeItemChildren(key: string): Observable<Array<ContentTreeItem>> {
@@ -44,7 +98,8 @@ export class UmbMediaStore extends UmbDataStoreBase<MediaDetails | ContentTreeIt
}
}
);
return this.items.pipe(map((items) => items.filter((item) => item.parentKey === key)));
// TODO: how do we handle trashed items?
return this.items.pipe(map((items) => items.filter((item) => item.parentKey === key && item.isTrashed === false)));
}
}