wip template repository

This commit is contained in:
Mads Rasmussen
2023-01-26 21:37:34 +01:00
parent c944568622
commit 69a9238d2a
4 changed files with 128 additions and 134 deletions

View File

@@ -18,36 +18,9 @@ export class UmbTemplateDetailStore extends UmbStoreBase {
super(host, UmbTemplateDetailStore.name);
}
getByKey(key: string) {
tryExecuteAndNotify(this._host, TemplateResource.getTemplateByKey({ key })).then(({ data }) => {
if (data) {
// TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)?
this.#data.append([data]);
}
});
return createObservablePart(this.#data, (items) => items.find((item) => item.key === key));
}
async save(template: Template) {
if (!template.key) return;
const { error } = await tryExecuteAndNotify(
this._host,
TemplateResource.putTemplateByKey({ key: template.key, requestBody: template })
);
if (error) throw error;
append(template: Template) {
this.#data.append([template]);
}
async create(template: TemplateCreateModel) {
const { data } = await tryExecuteAndNotify(this._host, TemplateResource.postTemplate({ requestBody: template }));
if (data) {
this.#data.append([data]);
}
}
}
export const UMB_TEMPLATE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbTemplateDetailStore>(

View File

@@ -0,0 +1,104 @@
import { v4 as uuid } from 'uuid';
import { UmbTemplateDetailStore, UMB_TEMPLATE_DETAIL_STORE_CONTEXT_TOKEN } from './template.detail.store';
import { Template, TemplateResource } from '@umbraco-cms/backend-api';
import { UmbContextConsumerController } from '@umbraco-cms/context-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/notification';
/* we need to new up the repository from within the element context. We want the correct context for
the notifications to be displayed in the correct place. */
// element -> context -> repository -> (store) -> data source
// TODO: implement data sources
export class UmbTemplateRepository {
#host: UmbControllerHostInterface;
#detailStore?: UmbTemplateDetailStore;
#notificationService?: UmbNotificationService;
constructor(host: UmbControllerHostInterface) {
this.#host = host;
new UmbContextConsumerController(this.#host, UMB_TEMPLATE_DETAIL_STORE_CONTEXT_TOKEN, (instance) => {
this.#detailStore = instance;
});
new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, (instance) => {
this.#notificationService = instance;
});
}
async new(parentKey: string | null): Promise<{ data?: Template; error?: unknown }> {
let masterTemplateAlias: string | undefined = undefined;
let error = undefined;
let data = undefined;
// TODO: can we do something so we don't have to call two endpoints?
if (parentKey) {
const { data: parentData, error: parentError } = await tryExecuteAndNotify(
this.#host,
TemplateResource.getTemplateByKey({ key: parentKey })
);
masterTemplateAlias = parentData?.alias;
error = parentError;
}
const { data: scaffoldData, error: scaffoldError } = await tryExecuteAndNotify(
this.#host,
TemplateResource.getTemplateScaffold({ masterTemplateAlias })
);
error = scaffoldError;
if (scaffoldData?.content) {
data = {
key: uuid(),
name: '',
alias: '',
content: scaffoldData?.content,
};
}
return { data, error };
}
async get(key: string): Promise<{ data?: Template; error?: unknown }> {
const { data, error } = await tryExecuteAndNotify(this.#host, TemplateResource.getTemplateByKey({ key }));
return { data, error };
}
async insert(template: Template): Promise<{ error?: unknown }> {
const payload = { requestBody: template };
const { error } = await tryExecuteAndNotify(this.#host, TemplateResource.postTemplate(payload));
if (!error) {
const notification = { data: { message: `Template created` } };
this.#notificationService?.peek('positive', notification);
}
this.#detailStore?.append(template);
return { error };
}
async update(template: Template): Promise<{ error?: unknown }> {
if (!template.key) {
return { error: 'Template key is missing' };
}
const payload = { key: template.key, requestBody: template };
const { error } = await tryExecuteAndNotify(this.#host, TemplateResource.putTemplateByKey(payload));
if (!error) {
const notification = { data: { message: `Template saved` } };
this.#notificationService?.peek('positive', notification);
}
this.#detailStore?.append(template);
return { error };
}
// TODO: delete
// TODO: tree
}

View File

@@ -1,19 +1,11 @@
import { v4 as uuid } from 'uuid';
import { UmbTemplateDetailStore, UMB_TEMPLATE_DETAIL_STORE_CONTEXT_TOKEN } from '../template.detail.store';
import { createObservablePart, DeepState, UmbObserverController } from '@umbraco-cms/observable-api';
import { Template, TemplateResource } from '@umbraco-cms/backend-api';
import { UmbContextConsumerController } from '@umbraco-cms/context-api';
import { UmbTemplateRepository } from '../template.repository';
import { createObservablePart, DeepState } from '@umbraco-cms/observable-api';
import { Template } from '@umbraco-cms/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/notification';
export class UmbTemplateWorkspaceContext {
#host: UmbControllerHostInterface;
#store?: UmbTemplateDetailStore;
#notificationService?: UmbNotificationService;
#storeObserver?: UmbObserverController;
#initResolver?: (value: unknown) => void;
ready = false;
#templateRepository: UmbTemplateRepository;
#data = new DeepState<Template | undefined>(undefined);
data = this.#data.asObservable();
@@ -22,16 +14,7 @@ export class UmbTemplateWorkspaceContext {
constructor(host: UmbControllerHostInterface) {
this.#host = host;
new UmbContextConsumerController(host, UMB_TEMPLATE_DETAIL_STORE_CONTEXT_TOKEN, (instance) => {
this.#store = instance;
this.ready = true;
this.#initResolver?.(true);
});
new UmbContextConsumerController(host, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, (instance) => {
this.#notificationService = instance;
});
this.#templateRepository = new UmbTemplateRepository(host);
}
setName(value: string) {
@@ -42,76 +25,21 @@ export class UmbTemplateWorkspaceContext {
this.#data.next({ ...this.#data.value, content: value });
}
init() {
return new Promise((resolve) => {
this.ready ? resolve(true) : (this.#initResolver = resolve);
});
}
load(entityKey: string) {
if (!this.ready || !this.#store) return;
this.#storeObserver?.destroy();
this.#storeObserver = new UmbObserverController(this.#host, this.#store.getByKey(entityKey), (data) => {
if (!data) return;
async load(entityKey: string) {
const { data } = await this.#templateRepository.get(entityKey);
if (data) {
this.#data.next(data);
});
}
}
async createScaffold(parentKey: string | null) {
if (!this.ready || !this.#store) return;
let masterTemplateAlias: string | undefined = undefined;
// TODO: handle errors
// TODO: can we do something so we don't have to call two endpoints?
if (parentKey) {
const { data: parentData } = await tryExecuteAndNotify(
this.#host,
TemplateResource.getTemplateByKey({ key: parentKey })
);
masterTemplateAlias = parentData?.alias;
}
const { data: scaffoldData } = await tryExecuteAndNotify(
this.#host,
TemplateResource.getTemplateScaffold({ masterTemplateAlias })
);
const template = {
key: uuid(),
name: '',
alias: '',
content: scaffoldData?.content,
};
this.#data.next(template);
const { data } = await this.#templateRepository.new(parentKey);
if (!data) return;
this.#data.next(data);
}
async create() {
// TODO: handle error
async save(isNew: boolean) {
if (!this.#data.value) return;
try {
await this.#store?.create(this.#data.value);
this.#notificationService?.peek('positive', { data: { message: `Template created` } });
} catch (error) {
console.log(error);
}
isNew ? this.#templateRepository.insert(this.#data.value) : this.#templateRepository.update(this.#data.value);
}
async update() {
// TODO: handle error
if (!this.#data.value) return;
try {
await this.#store?.save(this.#data.value);
this.#notificationService?.peek('positive', { data: { message: `Template saved` } });
} catch (error) {
console.log(error);
}
}
// TODO: add delete method
}

View File

@@ -22,14 +22,8 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
`,
];
private _entityKey!: string;
@property()
public get entityKey(): string {
return this._entityKey;
}
public set entityKey(value: string) {
this._entityKey = value;
}
public entityKey?: string;
@property()
public create?: string | null;
@@ -40,14 +34,13 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
@state()
private _content?: string | null = '';
private isNew = false;
#templateWorkspaceContext = new UmbTemplateWorkspaceContext(this);
async connectedCallback() {
super.connectedCallback();
// make sure the the context has received all dependencies
await this.#templateWorkspaceContext.init();
this.observe(this.#templateWorkspaceContext.name, (name) => {
this._name = name;
});
@@ -56,12 +49,15 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
this._content = content;
});
if (!this._entityKey && this.create !== undefined) {
if (!this.entityKey && this.create !== undefined) {
this.isNew = true;
this.#templateWorkspaceContext.createScaffold(this.create);
return;
}
this.#templateWorkspaceContext.load(this._entityKey);
if (this.entityKey) {
this.#templateWorkspaceContext.load(this.entityKey);
}
}
// TODO: temp code for testing create and save
@@ -78,13 +74,7 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
}
#onSave() {
this.#templateWorkspaceContext.update();
}
#onCreate() {
if (this.create !== undefined) {
this.#templateWorkspaceContext.create();
}
this.#templateWorkspaceContext.save(this.isNew);
}
render() {
@@ -93,7 +83,6 @@ export class UmbTemplateWorkspaceElement extends UmbLitElement {
<uui-input .value=${this._name} @input=${this.#onNameInput}></uui-input>
<uui-textarea id="content" .value=${this._content} @input="${this.#onTextareaInput}"></uui-textarea>
<uui-button label="Save" look="primary" color="positive" @click=${this.#onSave}></uui-button>
<uui-button label="Create" look="primary" color="positive" @click=${this.#onCreate}></uui-button>
</umb-workspace-layout>`;
}
}