add dictionary detail repo

This commit is contained in:
Mads Rasmussen
2024-01-30 21:16:51 +01:00
parent 4a9c3dc19c
commit 69f01d81ae
8 changed files with 212 additions and 93 deletions

View File

@@ -9,7 +9,7 @@ import type { UmbDetailStore } from '@umbraco-cms/backoffice/store';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export abstract class UmbDetailRepositoryBase<
DetailModelType extends { unique: string; entityType: string; parentUnique: string | null },
DetailModelType extends { unique: string; entityType: string; parentUnique?: string | null },
>
extends UmbRepositoryBase
implements UmbDetailRepository<DetailModelType>, UmbApi

View File

@@ -0,0 +1,11 @@
import type { UmbDictionaryDetailModel } from '../../types.js';
import { UmbDictionaryServerDataSource } from './dictionary-detail.server.data-source.js';
import { UMB_DICTIONARY_DETAIL_STORE_CONTEXT } from './dictionary-detail.store.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbDetailRepositoryBase } from '@umbraco-cms/backoffice/repository';
export class UmbDictionaryDetailRepository extends UmbDetailRepositoryBase<UmbDictionaryDetailModel> {
constructor(host: UmbControllerHost) {
super(host, UmbDictionaryServerDataSource, UMB_DICTIONARY_DETAIL_STORE_CONTEXT);
}
}

View File

@@ -0,0 +1,150 @@
import type { UmbDictionaryDetailModel } from '../../types.js';
import { UMB_DICTIONARY_ENTITY_TYPE } from '../../entity.js';
import { UmbId } from '@umbraco-cms/backoffice/id';
import type { UmbDetailDataSource } from '@umbraco-cms/backoffice/repository';
import type {
CreateDictionaryItemRequestModel,
DictionaryItemModelBaseModel,
} from '@umbraco-cms/backoffice/backend-api';
import { DictionaryResource } from '@umbraco-cms/backoffice/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* A data source for the Dictionary that fetches data from the server
* @export
* @class UmbDictionaryServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbDictionaryServerDataSource implements UmbDetailDataSource<UmbDictionaryDetailModel> {
#host: UmbControllerHost;
/**
* Creates an instance of UmbDictionaryServerDataSource.
* @param {UmbControllerHost} host
* @memberof UmbDictionaryServerDataSource
*/
constructor(host: UmbControllerHost) {
this.#host = host;
}
/**
* Creates a new Dictionary scaffold
* @return { CreateDictionaryRequestModel }
* @memberof UmbDictionaryServerDataSource
*/
async createScaffold() {
const data: UmbDictionaryDetailModel = {
entityType: UMB_DICTIONARY_ENTITY_TYPE,
unique: UmbId.new(),
name: '',
translations: [],
};
return { data };
}
/**
* Fetches a Dictionary with the given id from the server
* @param {string} unique
* @return {*}
* @memberof UmbDictionaryServerDataSource
*/
async read(unique: string) {
if (!unique) throw new Error('Unique is missing');
const { data, error } = await tryExecuteAndNotify(this.#host, DictionaryResource.getDictionaryById({ id: unique }));
if (error || !data) {
return { error };
}
// TODO: make data mapper to prevent errors
const dictionary: UmbDictionaryDetailModel = {
entityType: UMB_DICTIONARY_ENTITY_TYPE,
unique: data.id,
name: data.name,
translations: data.translations,
};
return { data: dictionary };
}
/**
* Inserts a new Dictionary on the server
* @param {UmbDictionaryDetailModel} model
* @return {*}
* @memberof UmbDictionaryServerDataSource
*/
async create(model: UmbDictionaryDetailModel) {
if (!model) throw new Error('Dictionary is missing');
// TODO: make data mapper to prevent errors
const requestBody: CreateDictionaryItemRequestModel = {
id: model.unique,
parentId: null,
name: model.name,
translations: model.translations,
};
const { data, error } = await tryExecuteAndNotify(
this.#host,
DictionaryResource.postDictionary({
requestBody,
}),
);
if (data) {
return this.read(data);
}
return { error };
}
/**
* Updates a Dictionary on the server
* @param {UmbDictionaryDetailModel} Dictionary
* @return {*}
* @memberof UmbDictionaryServerDataSource
*/
async update(model: UmbDictionaryDetailModel) {
if (!model.unique) throw new Error('Unique is missing');
// TODO: make data mapper to prevent errors
const requestBody: DictionaryItemModelBaseModel = {
name: model.name,
translations: model.translations,
};
const { data, error } = await tryExecuteAndNotify(
this.#host,
DictionaryResource.putDictionaryById({
id: model.unique,
requestBody,
}),
);
if (data) {
return this.read(data);
}
return { error };
}
/**
* Deletes a Dictionary on the server
* @param {string} unique
* @return {*}
* @memberof UmbDictionaryServerDataSource
*/
async delete(unique: string) {
if (!unique) throw new Error('Unique is missing');
return tryExecuteAndNotify(
this.#host,
DictionaryResource.deleteDictionaryById({
id: unique,
}),
);
}
}

View File

@@ -0,0 +1,25 @@
import type { UmbDictionaryDetailModel } from '../../types.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
/**
* @export
* @class UmbDictionaryDetailStore
* @extends {UmbStoreBase}
* @description - Data Store for Dictionary Details
*/
export class UmbDictionaryDetailStore extends UmbDetailStoreBase<UmbDictionaryDetailModel> {
/**
* Creates an instance of UmbDictionaryDetailStore.
* @param {UmbControllerHostElement} host
* @memberof UmbDictionaryDetailStore
*/
constructor(host: UmbControllerHostElement) {
super(host, UMB_DICTIONARY_DETAIL_STORE_CONTEXT.toString());
}
}
export const UMB_DICTIONARY_DETAIL_STORE_CONTEXT = new UmbContextToken<UmbDictionaryDetailStore>(
'UmbDictionaryDetailStore',
);

View File

@@ -0,0 +1,2 @@
export { UmbDictionaryDetailRepository } from './dictionary-detail.repository.js';
export { UMB_DICTIONARY_DETAIL_REPOSITORY_ALIAS } from './manifests.js';

View File

@@ -0,0 +1,23 @@
import { UmbDictionaryDetailRepository } from './dictionary-detail.repository.js';
import { UmbDictionaryDetailStore } from './dictionary-detail.store.js';
import type { ManifestRepository, ManifestStore } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_DICTIONARY_DETAIL_REPOSITORY_ALIAS = 'Umb.Repository.Dictionary.Detail';
const repository: ManifestRepository = {
type: 'repository',
alias: UMB_DICTIONARY_DETAIL_REPOSITORY_ALIAS,
name: 'Dictionary Detail Repository',
api: UmbDictionaryDetailRepository,
};
export const UMB_DICTIONARY_DETAIL_STORE_ALIAS = 'Umb.Store.Dictionary.Detail';
const store: ManifestStore = {
type: 'store',
alias: UMB_DICTIONARY_DETAIL_STORE_ALIAS,
name: 'Dictionary Detail Store',
api: UmbDictionaryDetailStore,
};
export const manifests = [repository, store];

View File

@@ -1,14 +1,7 @@
import { type UmbDictionaryTreeStore, UMB_DICTIONARY_TREE_STORE_CONTEXT } from '../tree/index.js';
import type { UmbDictionaryStore} from './dictionary.store.js';
import { UMB_DICTIONARY_STORE_CONTEXT } from './dictionary.store.js';
import { UmbDictionaryDetailServerDataSource } from './sources/dictionary-detail.server.data-source.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
import type {
CreateDictionaryItemRequestModel,
UpdateDictionaryItemRequestModel,
} from '@umbraco-cms/backoffice/backend-api';
import { type UmbNotificationContext, UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import { UmbTemporaryFileRepository } from '@umbraco-cms/backoffice/temporary-file';
@@ -18,27 +11,16 @@ export class UmbDictionaryRepository extends UmbBaseController implements UmbApi
#treeStore?: UmbDictionaryTreeStore;
#detailSource: UmbDictionaryDetailServerDataSource = new UmbDictionaryDetailServerDataSource(this);
#detailStore?: UmbDictionaryStore;
#temporaryFileRepository: UmbTemporaryFileRepository = new UmbTemporaryFileRepository(this);
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHost) {
super(host);
this.#init = Promise.all([
this.consumeContext(UMB_DICTIONARY_STORE_CONTEXT, (instance) => {
this.#detailStore = instance;
}),
this.consumeContext(UMB_DICTIONARY_TREE_STORE_CONTEXT, (instance) => {
this.#treeStore = instance;
}),
this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => {
this.#notificationContext = instance;
}),
]);
}
@@ -47,84 +29,11 @@ export class UmbDictionaryRepository extends UmbBaseController implements UmbApi
return this.#treeStore!.items(ids);
}
// DETAILS
// TODO: consider if we want to create a specific createScaffoldWithName, to loose the coupling to the model.
async createScaffold(parentId: string | null, preset?: Partial<CreateDictionaryItemRequestModel>) {
if (parentId === undefined) throw new Error('Parent id is missing');
await this.#init;
return this.#detailSource.createScaffold(parentId, preset);
}
async requestById(id: string) {
if (!id) throw new Error('Id is missing');
await this.#init;
const { data, error } = await this.#detailSource.read(id);
if (data) {
this.#detailStore?.append(data);
}
return { data, error };
}
async byId(id: string) {
if (!id) throw new Error('Key is missing');
await this.#init;
return this.#detailStore!.byId(id);
}
async list(skip = 0, take = 1000) {
await this.#init;
return this.#detailSource.list(skip, take);
}
async delete(id: string) {
await this.#init;
await this.#treeStore?.removeItem(id);
return this.#detailSource.delete(id);
}
async save(id: string, updatedDictionary: UpdateDictionaryItemRequestModel) {
if (!id) throw new Error('Id is missing');
if (!updatedDictionary) throw new Error('Dictionary is missing');
await this.#init;
const { error } = await this.#detailSource.update(id, updatedDictionary);
if (!error) {
// 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 dictionary is updated in the store while someone is editing it.
//this.#detailStore?.append(dictionary);
this.#treeStore?.updateItem(id, { name: updatedDictionary.name });
const notification = { data: { message: `Dictionary '${updatedDictionary.name}' saved` } };
this.#notificationContext?.peek('positive', notification);
}
return { error };
}
async create(detail: CreateDictionaryItemRequestModel) {
await this.#init;
if (!detail.name) {
throw new Error('Name is missing');
}
const { data, error } = await this.#detailSource.create(detail);
if (!error) {
const notification = { data: { message: `Dictionary '${detail.name}' created` } };
this.#notificationContext?.peek('positive', notification);
}
return { data, error };
}
async export(id: string, includeChildren = false) {
await this.#init;

View File

@@ -3,7 +3,6 @@ import type { UmbDictionaryEntityType } from './entity.js';
export interface UmbDictionaryDetailModel {
entityType: UmbDictionaryEntityType;
unique: string;
parentUnique: string | null;
name: string;
translations: Array<UmbDictionaryTranslationModel>;
}