Adds repository for member types (#525)
* member types repo * fix build --------- Co-authored-by: Mads Rasmussen <madsr@hey.com>
This commit is contained in:
@@ -23,8 +23,8 @@ import { UmbDocumentStore } from './documents/documents/repository/document.stor
|
||||
import { UmbDocumentTreeStore } from './documents/documents/repository/document.tree.store';
|
||||
import { UmbMediaDetailStore } from './media/media/repository/media.detail.store';
|
||||
import { UmbMediaTreeStore } from './media/media/repository/media.tree.store';
|
||||
import { UmbMemberTypeDetailStore } from './members/member-types/member-type.detail.store';
|
||||
import { UmbMemberTypeTreeStore } from './members/member-types/member-type.tree.store';
|
||||
import { UmbMemberTypeDetailStore } from './members/member-types/repository/member-type.detail.store';
|
||||
import { UmbMemberTypeTreeStore } from './members/member-types/repository/member-type.tree.store';
|
||||
import { UmbMemberGroupDetailStore } from './members/member-groups/repository/member-group.detail.store';
|
||||
import { UmbMemberGroupTreeStore } from './members/member-groups/repository/member-group.tree.store';
|
||||
import { UmbMemberDetailStore } from './members/members/member.detail.store';
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action';
|
||||
import { MEMBER_TYPES_REPOSITORY_ALIAS } from '../repository/manifests';
|
||||
import type { ManifestEntityAction } from '@umbraco-cms/models';
|
||||
|
||||
const entityType = 'member-type';
|
||||
const repositoryAlias = MEMBER_TYPES_REPOSITORY_ALIAS;
|
||||
|
||||
const entityActions: Array<ManifestEntityAction> = [
|
||||
{
|
||||
type: 'entityAction',
|
||||
alias: 'Umb.EntityAction.MemberType.Delete',
|
||||
name: 'Delete Member Type Entity Action',
|
||||
weight: 100,
|
||||
meta: {
|
||||
entityType,
|
||||
icon: 'umb:trash',
|
||||
label: 'Delete',
|
||||
repositoryAlias,
|
||||
api: UmbDeleteEntityAction,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const manifests = [...entityActions];
|
||||
@@ -1,5 +1,13 @@
|
||||
import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests';
|
||||
import { manifests as treeManifests } from './tree/manifests';
|
||||
import { manifests as respositoryManifests } from './repository/manifests';
|
||||
import { manifests as workspaceManifests } from './workspace/manifests';
|
||||
import { manifests as entityActionManifests } from './entity-actions/manifests';
|
||||
|
||||
export const manifests = [...sidebarMenuItemManifests, ...treeManifests, ...workspaceManifests];
|
||||
export const manifests = [
|
||||
...sidebarMenuItemManifests,
|
||||
...treeManifests,
|
||||
...respositoryManifests,
|
||||
...workspaceManifests,
|
||||
...entityActionManifests,
|
||||
];
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import type { MemberTypeDetails } from '@umbraco-cms/models';
|
||||
import { UmbContextToken } from '@umbraco-cms/context-api';
|
||||
import { ArrayState } from '@umbraco-cms/observable-api';
|
||||
import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/store';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
|
||||
|
||||
export const UMB_MEMBER_TYPE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMemberTypeDetailStore>('UmbMemberTypeDetailStore');
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbMemberTypeDetailStore
|
||||
* @extends {UmbStoreBase}
|
||||
* @description - Details Data Store for Member Types
|
||||
*/
|
||||
export class UmbMemberTypeDetailStore extends UmbStoreBase implements UmbEntityDetailStore<MemberTypeDetails> {
|
||||
|
||||
|
||||
#data = new ArrayState<MemberTypeDetails>([], (x) => x.key);
|
||||
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, UMB_MEMBER_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString());
|
||||
}
|
||||
|
||||
getScaffold(entityType: string, parentKey: string | null) {
|
||||
return {
|
||||
} as MemberTypeDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable.
|
||||
* @param {string} key
|
||||
* @return {*} {(Observable<MemberTypeDetails | undefined>)}
|
||||
* @memberof UmbMemberTypesStore
|
||||
*/
|
||||
getByKey(key: string) {
|
||||
return null as any;
|
||||
}
|
||||
|
||||
// TODO: make sure UI somehow can follow the status of this action.
|
||||
/**
|
||||
* @description - Save a Data Type.
|
||||
* @param {Array<MemberTypeDetails>} memberTypes
|
||||
* @memberof UmbMemberTypesStore
|
||||
* @return {*} {Promise<void>}
|
||||
*/
|
||||
save(data: MemberTypeDetails[]) {
|
||||
return null as any;
|
||||
}
|
||||
|
||||
// TODO: How can we avoid having this in both stores?
|
||||
/**
|
||||
* @description - Delete a Data Type.
|
||||
* @param {string[]} keys
|
||||
* @memberof UmbMemberTypesStore
|
||||
* @return {*} {Promise<void>}
|
||||
*/
|
||||
async delete(keys: string[]) {
|
||||
// TODO: use backend cli when available.
|
||||
return null as any;
|
||||
|
||||
this.#data.remove(keys);
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import { EntityTreeItemModel, MemberTypeResource } from '@umbraco-cms/backend-api';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
|
||||
import { UmbContextToken } from '@umbraco-cms/context-api';
|
||||
import { ArrayState } from '@umbraco-cms/observable-api';
|
||||
import { UmbStoreBase } from '@umbraco-cms/store';
|
||||
import type { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
|
||||
export const UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMemberTypeTreeStore>(
|
||||
'UmbMemberTypeTreeStore'
|
||||
);
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbMemberTypeTreeStore
|
||||
* @extends {UmbStoreBase}
|
||||
* @description - Tree Data Store for Member Types
|
||||
*/
|
||||
export class UmbMemberTypeTreeStore extends UmbStoreBase {
|
||||
// TODO: use the right type here:
|
||||
#data = new ArrayState<EntityTreeItemModel>([], (x) => x.key);
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
|
||||
}
|
||||
|
||||
// TODO: How can we avoid having this in both stores?
|
||||
/**
|
||||
* @description - Delete a Data Type.
|
||||
* @param {string[]} keys
|
||||
* @memberof UmbMemberTypesStore
|
||||
* @return {*} {Promise<void>}
|
||||
*/
|
||||
async delete(keys: string[]) {
|
||||
// TODO: use backend cli when available.
|
||||
await fetch('/umbraco/backoffice/member-type/delete', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(keys),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
this.#data.remove(keys);
|
||||
}
|
||||
|
||||
getTreeRoot() {
|
||||
tryExecuteAndNotify(this._host, MemberTypeResource.getTreeMemberTypeRoot({})).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.items);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: remove ignore when we know how to handle trashed items.
|
||||
return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null));
|
||||
}
|
||||
|
||||
getTreeItemChildren(key: string) {
|
||||
/*
|
||||
tryExecuteAndNotify(
|
||||
this._host,
|
||||
MemberTypeResource.getTreeMemberTypeChildren({
|
||||
parentKey: 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.items);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === key));
|
||||
}
|
||||
|
||||
getTreeItems(keys: Array<string>) {
|
||||
if (keys?.length > 0) {
|
||||
tryExecuteAndNotify(
|
||||
this._host,
|
||||
MemberTypeResource.getTreeMemberTypeItem({
|
||||
key: keys,
|
||||
})
|
||||
).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 this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? '')));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { UmbMemberTypeRepository } from './member-type.repository';
|
||||
import { ManifestRepository } from 'libs/extensions-registry/repository.models';
|
||||
|
||||
export const MEMBER_TYPES_REPOSITORY_ALIAS = 'Umb.Repository.MemberTypes';
|
||||
|
||||
const repository: ManifestRepository = {
|
||||
type: 'repository',
|
||||
alias: MEMBER_TYPES_REPOSITORY_ALIAS,
|
||||
name: 'Member Types Repository',
|
||||
class: UmbMemberTypeRepository,
|
||||
};
|
||||
|
||||
export const manifests = [repository];
|
||||
@@ -0,0 +1,33 @@
|
||||
import { UmbContextToken } from '@umbraco-cms/context-api';
|
||||
import { UmbStoreBase } from '@umbraco-cms/store';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
import { ArrayState } from '@umbraco-cms/observable-api';
|
||||
import type { MemberTypeDetails } from '@umbraco-cms/models';
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbMemberTypeDetailStore
|
||||
* @extends {UmbStoreBase}
|
||||
* @description - Details Data Store for Member Types
|
||||
*/
|
||||
export class UmbMemberTypeDetailStore
|
||||
extends UmbStoreBase
|
||||
{
|
||||
#data = new ArrayState<MemberTypeDetails>([], (x) => x.key);
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, UmbMemberTypeDetailStore.name);
|
||||
}
|
||||
|
||||
append(MemberType: MemberTypeDetails) {
|
||||
this.#data.append([MemberType]);
|
||||
}
|
||||
|
||||
remove(uniques: string[]) {
|
||||
this.#data.remove(uniques);
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEMBER_TYPE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMemberTypeDetailStore>(
|
||||
UmbMemberTypeDetailStore.name
|
||||
);
|
||||
@@ -0,0 +1,200 @@
|
||||
import { MemberTypeTreeServerDataSource } from './sources/member-type.tree.server.data';
|
||||
import { UmbMemberTypeTreeStore, UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN } from './member-type.tree.store';
|
||||
import { UmbMemberTypeDetailStore, UMB_MEMBER_TYPE_DETAIL_STORE_CONTEXT_TOKEN } from './member-type.detail.store';
|
||||
import { UmbMemberTypeDetailServerDataSource } from './sources/member-type.detail.server.data';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
import { UmbContextConsumerController } from '@umbraco-cms/context-api';
|
||||
import { RepositoryTreeDataSource, UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/repository';
|
||||
import { ProblemDetailsModel } from '@umbraco-cms/backend-api';
|
||||
import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/notification';
|
||||
import type { MemberTypeDetails } from '@umbraco-cms/models';
|
||||
|
||||
// TODO => use correct type when available
|
||||
type ItemType = any;
|
||||
|
||||
export class UmbMemberTypeRepository implements UmbTreeRepository, UmbDetailRepository<ItemType> {
|
||||
#init!: Promise<unknown>;
|
||||
|
||||
#host: UmbControllerHostInterface;
|
||||
|
||||
#treeSource: RepositoryTreeDataSource;
|
||||
#treeStore?: UmbMemberTypeTreeStore;
|
||||
|
||||
#detailSource: UmbMemberTypeDetailServerDataSource;
|
||||
#detailStore?: UmbMemberTypeDetailStore;
|
||||
|
||||
#notificationService?: UmbNotificationService;
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
this.#host = host;
|
||||
|
||||
// TODO: figure out how spin up get the correct data source
|
||||
this.#treeSource = new MemberTypeTreeServerDataSource(this.#host);
|
||||
this.#detailSource = new UmbMemberTypeDetailServerDataSource(this.#host);
|
||||
|
||||
this.#init = Promise.all([
|
||||
new UmbContextConsumerController(this.#host, UMB_MEMBER_TYPE_DETAIL_STORE_CONTEXT_TOKEN, (instance) => {
|
||||
this.#detailStore = instance;
|
||||
}),
|
||||
|
||||
new UmbContextConsumerController(this.#host, UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => {
|
||||
this.#treeStore = instance;
|
||||
}),
|
||||
|
||||
new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, (instance) => {
|
||||
this.#notificationService = instance;
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
async requestRootTreeItems() {
|
||||
await this.#init;
|
||||
|
||||
const { data, error } = await this.#treeSource.getRootItems();
|
||||
|
||||
if (data) {
|
||||
this.#treeStore?.appendItems(data.items);
|
||||
}
|
||||
|
||||
return { data, error, asObservable: () => this.#treeStore!.rootItems };
|
||||
}
|
||||
|
||||
async requestTreeItemsOf(parentKey: string | null) {
|
||||
await this.#init;
|
||||
|
||||
if (!parentKey) {
|
||||
const error: ProblemDetailsModel = { title: 'Parent key is missing' };
|
||||
return { data: undefined, error };
|
||||
}
|
||||
|
||||
const { data, error } = await this.#treeSource.getChildrenOf(parentKey);
|
||||
|
||||
if (data) {
|
||||
this.#treeStore?.appendItems(data.items);
|
||||
}
|
||||
|
||||
return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentKey) };
|
||||
}
|
||||
|
||||
async requestTreeItems(keys: Array<string>) {
|
||||
await this.#init;
|
||||
|
||||
if (!keys) {
|
||||
const error: ProblemDetailsModel = { title: 'Keys are missing' };
|
||||
return { data: undefined, error };
|
||||
}
|
||||
|
||||
const { data, error } = await this.#treeSource.getItems(keys);
|
||||
|
||||
return { data, error, asObservable: () => this.#treeStore!.items(keys) };
|
||||
}
|
||||
|
||||
async rootTreeItems() {
|
||||
await this.#init;
|
||||
return this.#treeStore!.rootItems;
|
||||
}
|
||||
|
||||
async treeItemsOf(parentKey: string | null) {
|
||||
await this.#init;
|
||||
return this.#treeStore!.childrenOf(parentKey);
|
||||
}
|
||||
|
||||
async treeItems(keys: Array<string>) {
|
||||
await this.#init;
|
||||
return this.#treeStore!.items(keys);
|
||||
}
|
||||
|
||||
// DETAILS
|
||||
|
||||
async createDetailsScaffold() {
|
||||
await this.#init;
|
||||
return this.#detailSource.createDetailsScaffold();
|
||||
}
|
||||
|
||||
async requestByKey(key: string) {
|
||||
await this.#init;
|
||||
|
||||
// TODO: should we show a notification if the key is missing?
|
||||
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
|
||||
if (!key) {
|
||||
const error: ProblemDetailsModel = { title: 'Key is missing' };
|
||||
return { error };
|
||||
}
|
||||
const { data, error } = await this.#detailSource.requestByKey(key);
|
||||
|
||||
if (data) {
|
||||
this.#detailStore?.append(data);
|
||||
}
|
||||
return { data, error };
|
||||
}
|
||||
|
||||
async delete(key: string) {
|
||||
await this.#init;
|
||||
|
||||
if (!key) {
|
||||
const error: ProblemDetailsModel = { title: 'Key is missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
const { error } = await this.#detailSource.delete(key);
|
||||
|
||||
if (!error) {
|
||||
const notification = { data: { message: `Member type deleted` } };
|
||||
this.#notificationService?.peek('positive', notification);
|
||||
}
|
||||
|
||||
// TODO: we currently don't use the detail store for anything.
|
||||
// Consider to look up the data before fetching from the server.
|
||||
// Consider notify a workspace if a member type is deleted from the store while someone is editing it.
|
||||
this.#detailStore?.remove([key]);
|
||||
this.#treeStore?.removeItem(key);
|
||||
// TODO: would be nice to align the stores on methods/methodNames.
|
||||
|
||||
return { error };
|
||||
}
|
||||
|
||||
async saveDetail(detail: ItemType) {
|
||||
await this.#init;
|
||||
|
||||
// TODO: should we show a notification if the MemberType is missing?
|
||||
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
|
||||
if (!detail || !detail.key) {
|
||||
const error: ProblemDetailsModel = { title: 'Member type is missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
const { error } = await this.#detailSource.saveDetail(detail);
|
||||
|
||||
if (!error) {
|
||||
const notification = { data: { message: `Member type '${detail.name}' saved` } };
|
||||
this.#notificationService?.peek('positive', notification);
|
||||
}
|
||||
|
||||
// TODO: we currently don't use the detail store for anything.
|
||||
// Consider to look up the data before fetching from the server
|
||||
// Consider notify a workspace if a member type is updated in the store while someone is editing it.
|
||||
this.#detailStore?.append(detail);
|
||||
this.#treeStore?.updateItem(detail.key, { name: detail.name });
|
||||
// TODO: would be nice to align the stores on methods/methodNames.
|
||||
|
||||
return { error };
|
||||
}
|
||||
|
||||
async createDetail(detail: MemberTypeDetails) {
|
||||
await this.#init;
|
||||
|
||||
if (!detail.name) {
|
||||
const error: ProblemDetailsModel = { title: 'Name is missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
const { data, error } = await this.#detailSource.createDetail(detail);
|
||||
|
||||
if (!error) {
|
||||
const notification = { data: { message: `Member type '${detail.name}' created` } };
|
||||
this.#notificationService?.peek('positive', notification);
|
||||
}
|
||||
|
||||
return { data, error };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { UmbContextToken } from '@umbraco-cms/context-api';
|
||||
import { UmbTreeStoreBase } from '@umbraco-cms/store';
|
||||
import type { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbMemberTypeTreeStore
|
||||
* @extends {UmbStoreBase}
|
||||
* @description - Tree Data Store for Member Types
|
||||
*/
|
||||
export class UmbMemberTypeTreeStore extends UmbTreeStoreBase {
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host, UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMemberTypeTreeStore>(
|
||||
UmbMemberTypeTreeStore.name
|
||||
);
|
||||
@@ -0,0 +1,116 @@
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
|
||||
import { ProblemDetailsModel } from '@umbraco-cms/backend-api';
|
||||
import type { MemberTypeDetails } from '@umbraco-cms/models';
|
||||
import { UmbDetailRepository } from '@umbraco-cms/repository';
|
||||
|
||||
/**
|
||||
* @description - A data source for the MemberType detail that fetches data from the server
|
||||
* @export
|
||||
* @class UmbMemberTypeDetailServerDataSource
|
||||
* @implements {MemberTypeDetailDataSource}
|
||||
*/
|
||||
export class UmbMemberTypeDetailServerDataSource implements UmbDetailRepository<MemberTypeDetails> {
|
||||
#host: UmbControllerHostInterface;
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
this.#host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Creates a new MemberType scaffold
|
||||
* @return {*}
|
||||
* @memberof UmbMemberTypeDetailServerDataSource
|
||||
*/
|
||||
async createDetailsScaffold() {
|
||||
const data = {} as MemberTypeDetails;
|
||||
return { data };
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Fetches a MemberType with the given key from the server
|
||||
* @param {string} key
|
||||
* @return {*}
|
||||
* @memberof UmbMemberTypeDetailServerDataSource
|
||||
*/
|
||||
requestByKey(key: string) {
|
||||
//return tryExecuteAndNotify(this.#host, MemberTypeResource.getMemberTypeByKey({ key }));
|
||||
// TODO => use backend cli when available.
|
||||
return tryExecuteAndNotify(this.#host, fetch(`/umbraco/management/api/v1/member-group/${key}`)) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Updates a MemberType on the server
|
||||
* @param {MemberTypeDetails} memberType
|
||||
* @return {*}
|
||||
* @memberof UmbMemberTypeDetailServerDataSource
|
||||
*/
|
||||
async saveDetail(memberType: MemberTypeDetails) {
|
||||
if (!memberType.key) {
|
||||
const error: ProblemDetailsModel = { title: 'MemberType key is missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
const payload = { key: memberType.key, requestBody: memberType };
|
||||
//return tryExecuteAndNotify(this.#host, MemberTypeResource.putMemberTypeByKey(payload));
|
||||
|
||||
// TODO => use backend cli when available.
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
fetch(`/umbraco/management/api/v1/member-type/${memberType.key}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Inserts a new MemberType on the server
|
||||
* @param {MemberTypeDetails} data
|
||||
* @return {*}
|
||||
* @memberof UmbMemberTypeDetailServerDataSource
|
||||
*/
|
||||
async createDetail(data: MemberTypeDetails) {
|
||||
const requestBody = {
|
||||
name: data.name,
|
||||
};
|
||||
|
||||
//return tryExecuteAndNotify(this.#host, MemberTypeResource.postMemberType({ requestBody }));
|
||||
// TODO => use backend cli when available.
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
fetch(`/umbraco/management/api/v1/member-type`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(requestBody),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Deletes a MemberType on the server
|
||||
* @param {string} key
|
||||
* @return {*}
|
||||
* @memberof UmbMemberTypeDetailServerDataSource
|
||||
*/
|
||||
async delete(key: string) {
|
||||
if (!key) {
|
||||
const error: ProblemDetailsModel = { title: 'Key is missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
//return await tryExecuteAndNotify(this.#host, MemberTypeResource.deleteMemberTypeByKey({ key }));
|
||||
// TODO => use backend cli when available.
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
fetch(`/umbraco/management/api/v1/member-type/${key}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
) as any;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { MemberTypeResource, ProblemDetailsModel } from '@umbraco-cms/backend-api';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
import { RepositoryTreeDataSource } from '@umbraco-cms/repository';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
|
||||
|
||||
/**
|
||||
* A data source for the MemberType tree that fetches data from the server
|
||||
* @export
|
||||
* @class MemberTypeTreeServerDataSource
|
||||
* @implements {MemberTypeTreeDataSource}
|
||||
*/
|
||||
export class MemberTypeTreeServerDataSource implements RepositoryTreeDataSource {
|
||||
#host: UmbControllerHostInterface;
|
||||
|
||||
/**
|
||||
* Creates an instance of MemberTypeTreeDataSource.
|
||||
* @param {UmbControllerHostInterface} host
|
||||
* @memberof MemberTypeTreeDataSource
|
||||
*/
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
this.#host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the root items for the tree from the server
|
||||
* @return {*}
|
||||
* @memberof MemberTypeTreeServerDataSource
|
||||
*/
|
||||
async getRootItems() {
|
||||
return tryExecuteAndNotify(this.#host, MemberTypeResource.getTreeMemberTypeRoot({}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the children of a given parent key from the server
|
||||
* @param {(string | null)} parentKey
|
||||
* @return {*}
|
||||
* @memberof MemberTypeTreeServerDataSource
|
||||
*/
|
||||
async getChildrenOf(parentKey: string | null) {
|
||||
const error: ProblemDetailsModel = { title: 'Not implemented for Member Type' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the items for the given keys from the server
|
||||
* @param {Array<string>} keys
|
||||
* @return {*}
|
||||
* @memberof MemberTypeTreeServerDataSource
|
||||
*/
|
||||
async getItems(keys: Array<string>) {
|
||||
if (!keys || keys.length === 0) {
|
||||
const error: ProblemDetailsModel = { title: 'Keys are missing' };
|
||||
return { error };
|
||||
}
|
||||
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
MemberTypeResource.getTreeMemberTypeItem({
|
||||
key: keys,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN } from '../member-type.tree.store';
|
||||
import { UmbMemberTypeRepository } from '../repository/member-type.repository';
|
||||
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
|
||||
|
||||
const treeAlias = 'Umb.Tree.MemberTypes';
|
||||
@@ -8,7 +8,7 @@ const tree: ManifestTree = {
|
||||
alias: treeAlias,
|
||||
name: 'Member Types Tree',
|
||||
meta: {
|
||||
storeAlias: UMB_MEMBER_TYPE_TREE_STORE_CONTEXT_TOKEN.toString(),
|
||||
repository: UmbMemberTypeRepository
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context';
|
||||
import { UmbWorkspaceEntityContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface';
|
||||
import { UmbMemberTypeRepository } from '../repository/member-type.repository';
|
||||
import { ObjectState } from '@umbraco-cms/observable-api';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
|
||||
// TODO => use correct tpye
|
||||
type EntityType = any;
|
||||
|
||||
export class UmbWorkspaceMemberTypeContext
|
||||
extends UmbWorkspaceContext
|
||||
implements UmbWorkspaceEntityContextInterface<EntityType | undefined>
|
||||
{
|
||||
#isNew = false;
|
||||
#host: UmbControllerHostInterface;
|
||||
#dataTypeRepository: UmbMemberTypeRepository;
|
||||
|
||||
#data = new ObjectState<EntityType | undefined>(undefined);
|
||||
name = this.#data.getObservablePart((data) => data?.name);
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
super(host);
|
||||
this.#host = host;
|
||||
this.#dataTypeRepository = new UmbMemberTypeRepository(this.#host);
|
||||
}
|
||||
|
||||
async load(entityKey: string) {
|
||||
const { data } = await this.#dataTypeRepository.requestByKey(entityKey);
|
||||
if (data) {
|
||||
this.#isNew = false;
|
||||
this.#data.next(data);
|
||||
}
|
||||
}
|
||||
|
||||
async createScaffold() {
|
||||
const { data } = await this.#dataTypeRepository.createDetailsScaffold();
|
||||
if (!data) return;
|
||||
this.#isNew = true;
|
||||
this.#data.next(data);
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.#data.getValue();
|
||||
}
|
||||
|
||||
getEntityKey() {
|
||||
return this.getData()?.key || '';
|
||||
}
|
||||
|
||||
getEntityType() {
|
||||
return 'member-type';
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.#data.update({ name });
|
||||
}
|
||||
|
||||
setPropertyValue(alias: string, value: unknown) {
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (!this.#data.value) return;
|
||||
if (this.#isNew) {
|
||||
await this.#dataTypeRepository.createDetail(this.#data.value);
|
||||
} else {
|
||||
await this.#dataTypeRepository.saveDetail(this.#data.value);
|
||||
}
|
||||
// If it went well, then its not new anymore?.
|
||||
this.#isNew = false;
|
||||
}
|
||||
|
||||
async delete(key: string) {
|
||||
await this.#dataTypeRepository.delete(key);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.#data.complete();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { UUIInputEvent, UUIInputElement } from '@umbraco-ui/uui';
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import '../../../shared/components/workspace/workspace-layout/workspace-layout.element';
|
||||
import { css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { UmbWorkspaceMemberTypeContext } from './member-type-workspace.context';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
@customElement('umb-member-type-workspace')
|
||||
export class UmbMemberTypeWorkspaceElement extends LitElement {
|
||||
export class UmbMemberTypeWorkspaceElement extends UmbLitElement {
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
css`
|
||||
@@ -14,14 +15,61 @@ export class UmbMemberTypeWorkspaceElement extends LitElement {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#header {
|
||||
/* TODO: can this be applied from layout slot CSS? */
|
||||
margin: 0 var(--uui-size-layout-1);
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@property()
|
||||
id!: string;
|
||||
|
||||
|
||||
@state()
|
||||
private _memberTypeName = '';
|
||||
|
||||
@state()
|
||||
private _unique?: string;
|
||||
|
||||
#workspaceContext: UmbWorkspaceMemberTypeContext = new UmbWorkspaceMemberTypeContext(this);
|
||||
|
||||
public load(entityKey: string) {
|
||||
this.#workspaceContext?.load(entityKey);
|
||||
this._unique = entityKey;
|
||||
}
|
||||
|
||||
public create() {
|
||||
this.#workspaceContext.createScaffold();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.provideContext('umbWorkspaceContext', this.#workspaceContext);
|
||||
this.observe(this.#workspaceContext.name, (memberTypeName) => {
|
||||
if (memberTypeName !== this._memberTypeName) {
|
||||
this._memberTypeName = memberTypeName ?? '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO. find a way where we don't have to do this for all Workspaces.
|
||||
private _handleInput(event: UUIInputEvent) {
|
||||
if (event instanceof UUIInputEvent) {
|
||||
const target = event.composedPath()[0] as UUIInputElement;
|
||||
|
||||
if (typeof target?.value === 'string') {
|
||||
this.#workspaceContext.setName(target.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` <umb-workspace-layout alias="Umb.Workspace.MemberType">Member Type Workspace</umb-workspace-layout> `;
|
||||
return html`
|
||||
<umb-workspace-layout alias="Umb.Workspace.MemberType">
|
||||
<uui-input id="header" slot="header" .value=${this._unique} @input="${this._handleInput}"></uui-input>
|
||||
</umb-workspace-layout>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action';
|
||||
import { UmbMoveEntityAction } from '../../../../backoffice/shared/entity-actions/move/move.action';
|
||||
import { DICTIONARY_REPOSITORY_ALIAS } from '../repository/manifests';
|
||||
import UmbReloadDictionaryEntityAction from './reload.action';
|
||||
import UmbImportDictionaryEntityAction from './import/import.action';
|
||||
import UmbExportDictionaryEntityAction from './export/export.action';
|
||||
@@ -7,7 +8,7 @@ import UmbCreateDictionaryEntityAction from './create/create.action';
|
||||
import type { ManifestEntityAction } from '@umbraco-cms/models';
|
||||
|
||||
const entityType = 'dictionary-item';
|
||||
const repositoryAlias = 'Umb.Repository.Dictionary';
|
||||
const repositoryAlias = DICTIONARY_REPOSITORY_ALIAS;
|
||||
|
||||
const entityActions: Array<ManifestEntityAction> = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user