wip repositories

This commit is contained in:
Mads Rasmussen
2024-03-22 09:32:20 +01:00
parent b9e69310af
commit 1f421a24f8
29 changed files with 184 additions and 349 deletions

View File

@@ -1,5 +1,5 @@
import type { UmbRelationTypeCollectionFilterModel } from '../types.js';
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from '../../repository/detail/types.js';
import { UMB_RELATION_TYPE_ENTITY_TYPE } from '../../entity.js';
import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection';
import { RelationTypeResource } from '@umbraco-cms/backoffice/external/backend-api';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from '../../repository/detail/types.js';
import type { UmbRelationTypeCollectionFilterModel } from '../types.js';
import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeDetailModel } from '../../../types.js';
import type { UmbRelationTypeDetailModel } from '../../../repository/detail/types.js';
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from './types.js';
import { UmbRelationTypeServerDataSource } from './relation-type-detail.server.data-source.js';
import { UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT } from './relation-type-detail.store.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from './types.js';
import { UMB_RELATION_TYPE_ENTITY_TYPE } from '../../entity.js';
import { RelationTypeResource } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from './types.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

View File

@@ -1,4 +1,4 @@
import type { UmbRelationTypeEntityType } from './entity.js';
import type { UmbRelationTypeEntityType } from '../../entity.js';
export interface UmbRelationTypeDetailModel {
alias: string;

View File

@@ -14,31 +14,13 @@ const workspace: ManifestWorkspaces = {
const workspaceViews: Array<ManifestWorkspaceView> = [
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.RelationType.RelationType',
name: 'Relation Type Workspace RelationType View',
js: () => import('./views/relation-type/relation-type-workspace-view-relation-type.element.js'),
alias: 'Umb.WorkspaceView.RelationType.Details',
name: 'Relation Type Details Workspace View',
js: () => import('./views/details/relation-type-details-workspace-view.element.js'),
weight: 20,
meta: {
label: 'RelationType',
pathname: 'relation-type',
icon: 'icon-info',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: workspace.alias,
},
],
},
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.RelationType.Relation',
name: 'Relation Type Workspace Relation View',
js: () => import('./views/relation/workspace-view-relation-type-relation.element.js'),
weight: 10,
meta: {
label: 'Relation',
pathname: 'relation',
label: 'Details',
pathname: 'details',
icon: 'icon-trafic',
},
conditions: [

View File

@@ -1,5 +1,5 @@
import { UmbRelationTypeDetailRepository } from '../../repository/detail/index.js';
import type { UmbRelationTypeDetailModel } from '../../types.js';
import type { UmbRelationTypeDetailModel } from '../../repository/detail/types.js';
import { UmbRelationTypeWorkspaceEditorElement } from './relation-type-workspace-editor.element.js';
import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from './relation-type-workspace.context-token.js';
import { UmbWorkspaceRouteManager } from '@umbraco-cms/backoffice/workspace';

View File

@@ -5,6 +5,7 @@ import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { RelationResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import UmbRelationDetailRepository from 'src/packages/relations/relations/repository/relation.repository.js';
@customElement('umb-workspace-view-relation-type-relation')
export class UmbWorkspaceViewRelationTypeRelationElement extends UmbLitElement implements UmbWorkspaceViewElement {
@@ -13,23 +14,23 @@ export class UmbWorkspaceViewRelationTypeRelationElement extends UmbLitElement i
_relations: Array<RelationResponseModel> = [];
#workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE;
#relationDetailRepository = new UmbRelationDetailRepository(this);
constructor() {
super();
this.consumeContext(UMB_RELATION_TYPE_WORKSPACE_CONTEXT, (instance) => {
this.#workspaceContext = instance;
this.#getRelations();
this.#requestRelations();
});
}
async #getRelations() {
async #requestRelations() {
if (!this.#workspaceContext) {
return;
}
const response = await this.#workspaceContext.getRelations();
this._relations = response.data?.items ?? [];
const { data, error } = await this.#relationDetailRepository.read(this.#workspaceContext.unique);
}
private _tableConfig: UmbTableConfig = {
@@ -59,15 +60,15 @@ export class UmbWorkspaceViewRelationTypeRelationElement extends UmbLitElement i
private get _tableItems(): UmbTableItem[] {
return this._relations.map((relation) => {
return {
id: relation.parentId + '-' + relation.childId, // Add the missing id property
id: relation.unique + '-' + relation.childId, // Add the missing id property
data: [
{
columnAlias: 'parent',
value: relation.parentName,
value: relation.parent.name,
},
{
columnAlias: 'child',
value: relation.childName,
value: relation.child.name,
},
{
columnAlias: 'created',
@@ -83,17 +84,28 @@ export class UmbWorkspaceViewRelationTypeRelationElement extends UmbLitElement i
}
render() {
return html`<uui-box headline="Relations">
<umb-table .config=${this._tableConfig} .columns=${this._tableColumns} .items=${this._tableItems}></umb-table>
</uui-box>`;
return html`${this.#renderRelations()}${this.#renderDetails()}`;
}
#renderRelations() {
return html` <umb-table
.config=${this._tableConfig}
.columns=${this._tableColumns}
.items=${this._tableItems}></umb-table>`;
}
#renderDetails() {
return html`<uui-box>Details</uui-box>`;
}
static styles = [
UmbTextStyles,
css`
:host {
display: block;
margin: var(--uui-size-layout-1);
display: grid;
gap: var(--uui-size-layout-1);
padding: var(--uui-size-layout-1);
grid-template-columns: 1fr 350px;
}
`,
];

View File

@@ -1,122 +0,0 @@
import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from '../../relation-type-workspace.context-token.js';
import type {
UUIBooleanInputEvent,
UUIRadioGroupElement,
UUIRadioGroupEvent,
UUISelectEvent,
UUIToggleElement,
} from '@umbraco-cms/backoffice/external/uui';
import { css, html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { RelationTypeResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
import '@umbraco-cms/backoffice/object-type';
@customElement('umb-relation-type-workspace-view-relation-type')
export class UmbRelationTypeWorkspaceViewRelationTypeElement extends UmbLitElement implements UmbWorkspaceViewElement {
@state()
private _relationType?: RelationTypeResponseModel;
#workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE;
constructor() {
super();
this.consumeContext(UMB_RELATION_TYPE_WORKSPACE_CONTEXT, (instance) => {
this.#workspaceContext = instance;
this._observeRelationType();
});
}
private _observeRelationType() {
if (!this.#workspaceContext) {
return;
}
this.observe(this.#workspaceContext.data, (relationType) => {
if (!relationType) return;
this._relationType = relationType;
});
}
#handleDirectionChange(event: UUIRadioGroupEvent) {
const target = event.target as UUIRadioGroupElement;
const value = target.value === 'true';
this.#workspaceContext?.update('isBidirectional', value);
}
#handleIsDependencyChange(event: UUIBooleanInputEvent) {
const target = event.target as UUIToggleElement;
const value = target.checked;
this.#workspaceContext?.update('isDependency', value);
}
render() {
return html`
<uui-box>
<umb-property-layout label="Direction">
<uui-radio-group
value=${ifDefined(this._relationType?.isBidirectional)}
@change=${this.#handleDirectionChange}
slot="editor">
<uui-radio label="Parent to child" value="false"></uui-radio>
<uui-radio label="Bidirectional" value="true"></uui-radio>
</uui-radio-group>
</umb-property-layout>
<umb-property-layout label="Parent">${this.#renderParentProperty()}</umb-property-layout>
<umb-property-layout label="Child"> ${this.#renderChildProperty()} </umb-property-layout>
<umb-property-layout label="Is dependency">
<uui-toggle
slot="editor"
@change=${this.#handleIsDependencyChange}
.checked=${this._relationType?.isDependency ?? false}></uui-toggle>
</umb-property-layout>
</uui-box>
`;
}
#onParentObjectTypeChange(event: UUISelectEvent) {
const value = event.target.value as string;
this.#workspaceContext?.update('parentObjectType', value);
}
#onChildObjectTypeChange(event: UUISelectEvent) {
const value = event.target.value as string;
this.#workspaceContext?.update('childObjectType', value);
}
#renderParentProperty() {
if (!this.#workspaceContext?.getIsNew() && this._relationType)
return html`<div slot="editor">${this._relationType.parentObjectTypeName}</div>`;
return html`
<umb-input-object-type @change=${this.#onParentObjectTypeChange} slot="editor"></umb-input-object-type>
`;
}
#renderChildProperty() {
if (!this.#workspaceContext?.getIsNew() && this._relationType)
return html`<div slot="editor">${this._relationType.childObjectTypeName}</div>`;
return html`
<umb-input-object-type @change=${this.#onChildObjectTypeChange} slot="editor"></umb-input-object-type>
`;
}
static styles = [
css`
:host {
display: block;
margin: var(--uui-size-layout-1);
}
`,
];
}
export default UmbRelationTypeWorkspaceViewRelationTypeElement;
declare global {
interface HTMLElementTagNameMap {
'umb-relation-type-workspace-view-relation-type': UmbRelationTypeWorkspaceViewRelationTypeElement;
}
}

View File

@@ -1,26 +0,0 @@
import type { Meta, Story } from '@storybook/web-components';
import type { UmbRelationTypeWorkspaceViewRelationTypeElement } from './relation-type-workspace-view-relation-type.element.js';
import { html } from '@umbraco-cms/backoffice/external/lit';
//import { data } from '../../../../../core/mocks/data/relation-type.data.js';
import './relation-type-workspace-view-relation-type.element.js';
//import { UmbRelationTypeWorkspaceContext } from '../../workspace-relation-type.context.js';
export default {
title: 'Workspaces/Relation Type/Views/RelationType',
component: 'umb-relation-type-workspace-view-relation-type',
id: 'umb-relation-type-workspace-view-relation-type',
decorators: [
(story) => {
return html`TODO: make use of mocked workspace context??`;
/*html` <umb-context-provider key="umbRelationTypeContext" .value=${new UmbRelationTypeWorkspaceContext(data[0])}>
${story()}
</umb-context-provider>`,*/
},
],
} as Meta;
export const AAAOverview: Story<UmbRelationTypeWorkspaceViewRelationTypeElement> = () =>
html` <umb-relation-type-workspace-view-relation-type></umb-relation-type-workspace-view-relation-type>`;
AAAOverview.storyName = 'Overview';

View File

@@ -1,26 +0,0 @@
import './workspace-view-relation-type-relation.element.js';
import type { Meta, Story } from '@storybook/web-components';
import type { UmbWorkspaceViewRelationTypeRelationElement } from './workspace-view-relation-type-relation.element.js';
import { html } from '@umbraco-cms/backoffice/external/lit';
//import { data } from '../../../../../core/mocks/data/relation-type.data.js';
//import { UmbRelationTypeContext } from '../../relation-type.context.js';
export default {
title: 'Workspaces/Relation Type/Views/Relation',
component: 'umb-workspace-view-relation-type-relation',
id: 'umb-workspace-view-relation-type-relation',
decorators: [
(story) => {
return html`TODO: make use of mocked workspace context??`;
/*html` <umb-context-provider key="umbRelationTypeContext" .value=${new UmbRelationTypeWorkspaceContext(data[0])}>
${story()}
</umb-context-provider>`,*/
},
],
} as Meta;
export const AAAOverview: Story<UmbWorkspaceViewRelationTypeRelationElement> = () =>
html` <umb-workspace-view-relation-type-relation></umb-workspace-view-relation-type-relation>`;
AAAOverview.storyName = 'Overview';

View File

@@ -0,0 +1 @@
export { UmbRelationCollectionRepository } from './repository/index.js';

View File

@@ -0,0 +1,3 @@
import { manifests as collectionRepositoryManifests } from './repository/manifests.js';
export const manifests = [collectionRepositoryManifests];

View File

@@ -0,0 +1,2 @@
export { UMB_RELATION_COLLECTION_REPOSITORY_ALIAS } from './manifests.js';
export { UmbRelationCollectionRepository } from './relation-collection.repository.js';

View File

@@ -0,0 +1,12 @@
import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_RELATION_COLLECTION_REPOSITORY_ALIAS = 'Umb.Repository.Relation.Collection';
const repository: ManifestRepository = {
type: 'repository',
alias: UMB_RELATION_COLLECTION_REPOSITORY_ALIAS,
name: 'Relation Collection Repository',
api: () => import('./relation-collection.repository.js'),
};
export const manifests = [repository];

View File

@@ -0,0 +1,21 @@
import type { UmbRelationCollectionFilterModel } from '../types.js';
import { UmbRelationCollectionServerDataSource } from './relation-collection.server.data-source.js';
import type { UmbRelationCollectionDataSource } from './types.js';
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbRelationCollectionRepository implements UmbCollectionRepository {
#collectionSource: UmbRelationCollectionDataSource;
constructor(host: UmbControllerHost) {
this.#collectionSource = new UmbRelationCollectionServerDataSource(host);
}
async requestCollection(filter: UmbRelationCollectionFilterModel) {
return this.#collectionSource.getCollection(filter);
}
destroy(): void {}
}
export default UmbRelationCollectionRepository;

View File

@@ -0,0 +1,70 @@
import type { UmbRelationCollectionFilterModel } from '../types.js';
import type { UmbRelationDetailModel } from '../../types.js';
import { UMB_RELATION_ENTITY_TYPE } from '../../entity.js';
import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection';
import { RelationResource } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* A data source that fetches the relation collection data from the server.
* @export
* @class UmbRelationCollectionServerDataSource
* @implements {UmbCollectionDataSource}
*/
export class UmbRelationCollectionServerDataSource implements UmbCollectionDataSource<UmbRelationDetailModel> {
#host: UmbControllerHost;
/**
* Creates an instance of UmbRelationCollectionServerDataSource.
* @param {UmbControllerHost} host
* @memberof UmbRelationCollectionServerDataSource
*/
constructor(host: UmbControllerHost) {
this.#host = host;
}
/**
* Gets the relation collection filtered by the given filter.
* @param {UmbRelationCollectionFilterModel} filter
* @return {*}
* @memberof UmbRelationCollectionServerDataSource
*/
async getCollection(filter: UmbRelationCollectionFilterModel) {
const requestBody = {
skip: filter.skip,
take: filter.take,
id: filter.relationType.unique,
};
const { data, error } = await tryExecuteAndNotify(this.#host, RelationResource.getRelationTypeById(requestBody));
if (data) {
const items = data.items.map((item) => {
const model: UmbRelationDetailModel = {
unique: item.id,
entityType: UMB_RELATION_ENTITY_TYPE,
relationType: {
unique: item.relationType.id,
},
parent: {
unique: item.parent.id,
name: item.parent.name || '',
},
child: {
unique: item.child.id,
name: item.child.name || '',
},
createDate: item.createDate,
comment: item.comment || '',
};
return model;
});
return { data: { items, total: data.total } };
}
return { error };
}
}

View File

@@ -0,0 +1,8 @@
import type { UmbRelationDetailModel } from '../../types.js';
import type { UmbRelationCollectionFilterModel } from '../types.js';
import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection';
export type UmbRelationTypeCollectionDataSource = UmbCollectionDataSource<
UmbRelationDetailModel,
UmbRelationCollectionFilterModel
>;

View File

@@ -0,0 +1,7 @@
export interface UmbRelationCollectionFilterModel {
relationType: {
unique: string;
};
skip?: number;
take?: number;
}

View File

@@ -1 +0,0 @@
export const UMB_RELATION_ENTITY_TYPE = 'relation';

View File

@@ -0,0 +1,3 @@
export const UMB_RELATION_ENTITY_TYPE = 'relation';
export type UmbRelationEntityType = typeof UMB_RELATION_ENTITY_TYPE;

View File

@@ -1,2 +1,2 @@
export * from './repository/index.js';
export * from './entities.js';
export * from './entity.js';

View File

@@ -1 +0,0 @@
export * from './relation.repository.js';

View File

@@ -1,12 +0,0 @@
import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_RELATION_REPOSITORY_ALIAS = 'Umb.Repository.Relation';
const repository: ManifestRepository = {
type: 'repository',
alias: UMB_RELATION_REPOSITORY_ALIAS,
name: 'Relation Repository',
api: () => import('./relation.repository.js'),
};
export const manifests = [repository];

View File

@@ -1,56 +0,0 @@
import { UmbRelationServerDataSource } from './sources/relation.server.data.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbNotificationContext } from '@umbraco-cms/backoffice/notification';
import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbRelationRepository extends UmbControllerBase implements UmbApi {
#init!: Promise<unknown>;
#detailDataSource: UmbRelationServerDataSource;
#notificationContext?: UmbNotificationContext;
constructor(host: UmbControllerHost) {
super(host);
// TODO: figure out how spin up get the correct data source
this.#detailDataSource = new UmbRelationServerDataSource(this._host);
this.#init = Promise.all([
this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => {
this.#notificationContext = instance;
}).asPromise(),
]);
}
async requestById(id: string) {
await this.#init;
// TODO: should we show a notification if the id is missing?
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
if (!id) {
throw new Error('Id is missing');
}
const { data, error } = await this.#detailDataSource.read(id);
return { data, error };
}
async requestChildRelationById(childId: string, relationTypeAlias?: string) {
await this.#init;
// TODO: should we show a notification if the id is missing?
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
if (!childId) {
throw new Error('Id is missing');
}
const { data, error } = await this.#detailDataSource.readChildRelations(childId, relationTypeAlias);
return { data, error };
}
}
export default UmbRelationRepository;

View File

@@ -1,61 +0,0 @@
import { RelationResource } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* A data source for the Relation that fetches data from the server
* @export
* @class UmbRelationServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbRelationServerDataSource {
#host: UmbControllerHost;
/**
* Creates an instance of UmbRelationServerDataSource.
* @param {UmbControllerHost} host
* @memberof UmbRelationServerDataSource
*/
constructor(host: UmbControllerHost) {
this.#host = host;
}
/**
* Fetches relations by the given id from the server
* @param {string} id
* @return {*}
* @memberof UmbRelationServerDataSource
*/
async read(id: string) {
if (!id) {
throw new Error('Id is missing');
}
return tryExecuteAndNotify(
this.#host,
RelationResource.getRelationTypeById({
id,
}),
);
}
/**
* Fetches relations by the given id from the server
* @param {string} childId
* @return {*}
* @memberof UmbRelationServerDataSource
*/
async readChildRelations(childId: string, relationTypeAlias?: string) {
if (!childId) {
throw new Error('Id is missing');
}
return tryExecuteAndNotify(
this.#host,
RelationResource.getRelationChildRelationByChildId({
childId,
relationTypeAlias,
}),
);
}
}

View File

@@ -0,0 +1,19 @@
import type { UmbRelationEntityType } from './entity.js';
export interface UmbRelationDetailModel {
unique: string;
entityType: UmbRelationEntityType;
relationType: {
unique: string;
};
parent: {
unique: string;
name: string;
};
child: {
unique: string;
name: string;
};
createDate: string;
comment: string | null;
}