Skip to content

Commit f8c1b9a

Browse files
authored
Merge pull request #2339 from umbraco/v15/fix/extend-entity-detail-workspace-base
Fix: implement UmbEntityDetailWorkspaceContextBase across all non content workspaces
2 parents dfb8aef + 8fbac95 commit f8c1b9a

File tree

11 files changed

+284
-827
lines changed

11 files changed

+284
-827
lines changed

src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts

Lines changed: 68 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,23 @@ export interface UmbEntityWorkspaceContextArgs {
2020
detailRepositoryAlias: string;
2121
}
2222

23-
export interface UmbEntityDetailWorkspaceContextCreateArgs {
23+
export interface UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> {
2424
parent: UmbEntityModel;
25+
preset?: Partial<DetailModelType>;
2526
}
2627

2728
export abstract class UmbEntityDetailWorkspaceContextBase<
28-
EntityModelType extends UmbEntityModel,
29-
DetailRepositoryType extends UmbDetailRepository<EntityModelType> = UmbDetailRepository<EntityModelType>,
30-
> extends UmbSubmittableWorkspaceContextBase<EntityModelType> {
29+
DetailModelType extends UmbEntityModel,
30+
DetailRepositoryType extends UmbDetailRepository<DetailModelType> = UmbDetailRepository<DetailModelType>,
31+
CreateArgsType extends
32+
UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> = UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType>,
33+
> extends UmbSubmittableWorkspaceContextBase<DetailModelType> {
3134
/**
3235
* @description Data manager for the workspace.
3336
* @protected
3437
* @memberof UmbEntityWorkspaceContextBase
3538
*/
36-
protected readonly _data = new UmbEntityWorkspaceDataManager<EntityModelType>(this);
39+
protected readonly _data = new UmbEntityWorkspaceDataManager<DetailModelType>(this);
3740

3841
protected _getDataPromise?: Promise<any>;
3942

@@ -79,7 +82,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
7982
await this.#init;
8083
this.resetState();
8184
this._getDataPromise = this._detailRepository!.requestByUnique(unique);
82-
type GetDataType = Awaited<ReturnType<UmbDetailRepository<EntityModelType>['requestByUnique']>>;
85+
type GetDataType = Awaited<ReturnType<UmbDetailRepository<DetailModelType>['requestByUnique']>>;
8386
const response = (await this._getDataPromise) as GetDataType;
8487
const data = response.data;
8588

@@ -96,58 +99,11 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
9699
return this._getDataPromise;
97100
}
98101

99-
async submit() {
100-
await this.#init;
101-
const currentData = this._data.getCurrent();
102-
103-
if (!currentData) {
104-
throw new Error('Data is not set');
105-
}
106-
if (!currentData.unique) {
107-
throw new Error('Unique is not set');
108-
}
109-
110-
if (this.getIsNew()) {
111-
const parent = this.#parent.getValue();
112-
if (!parent) throw new Error('Parent is not set');
113-
const { error, data } = await this._detailRepository!.create(currentData, parent.unique);
114-
if (error || !data) {
115-
throw error?.message ?? 'Repository did not return data after create.';
116-
}
117-
118-
this._data.setPersisted(data);
119-
120-
// TODO: this might not be the right place to alert the tree, but it works for now
121-
const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
122-
const event = new UmbRequestReloadChildrenOfEntityEvent({
123-
entityType: parent.entityType,
124-
unique: parent.unique,
125-
});
126-
eventContext.dispatchEvent(event);
127-
this.setIsNew(false);
128-
} else {
129-
const { error, data } = await this._detailRepository!.save(currentData);
130-
if (error || !data) {
131-
throw error?.message ?? 'Repository did not return data after create.';
132-
}
133-
134-
this._data.setPersisted(data);
135-
136-
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
137-
const event = new UmbRequestReloadStructureForEntityEvent({
138-
unique: this.getUnique()!,
139-
entityType: this.getEntityType(),
140-
});
141-
142-
actionEventContext.dispatchEvent(event);
143-
}
144-
}
145-
146-
async create(args: UmbEntityDetailWorkspaceContextCreateArgs) {
102+
async createScaffold(args: CreateArgsType) {
147103
await this.#init;
148104
this.resetState();
149105
this.#parent.setValue(args.parent);
150-
const request = this._detailRepository!.createScaffold();
106+
const request = this._detailRepository!.createScaffold(args.preset);
151107
this._getDataPromise = request;
152108
let { data } = await request;
153109
if (!data) return undefined;
@@ -161,6 +117,25 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
161117
return data;
162118
}
163119

120+
async submit() {
121+
await this.#init;
122+
const currentData = this._data.getCurrent();
123+
124+
if (!currentData) {
125+
throw new Error('Data is not set');
126+
}
127+
128+
if (currentData.unique === undefined) {
129+
throw new Error('Unique is not set');
130+
}
131+
132+
if (this.getIsNew()) {
133+
this.#create(currentData);
134+
} else {
135+
this.#update(currentData);
136+
}
137+
}
138+
164139
async delete(unique: string) {
165140
await this.#init;
166141
await this._detailRepository!.delete(unique);
@@ -179,6 +154,44 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
179154
return !newUrl.includes(currentWorkspacePathIdentifier);
180155
}
181156

157+
async #create(currentData: DetailModelType) {
158+
const parent = this.#parent.getValue();
159+
if (!parent) throw new Error('Parent is not set');
160+
const { error, data } = await this._detailRepository!.create(currentData, parent.unique);
161+
if (error || !data) {
162+
throw error?.message ?? 'Repository did not return data after create.';
163+
}
164+
165+
this._data.setPersisted(data);
166+
this._data.setCurrent(data);
167+
168+
const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
169+
const event = new UmbRequestReloadChildrenOfEntityEvent({
170+
entityType: parent.entityType,
171+
unique: parent.unique,
172+
});
173+
eventContext.dispatchEvent(event);
174+
this.setIsNew(false);
175+
}
176+
177+
async #update(currentData: DetailModelType) {
178+
const { error, data } = await this._detailRepository!.save(currentData);
179+
if (error || !data) {
180+
throw error?.message ?? 'Repository did not return data after create.';
181+
}
182+
183+
this._data.setPersisted(data);
184+
this._data.setCurrent(data);
185+
186+
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
187+
const event = new UmbRequestReloadStructureForEntityEvent({
188+
unique: this.getUnique()!,
189+
entityType: this.getEntityType(),
190+
});
191+
192+
actionEventContext.dispatchEvent(event);
193+
}
194+
182195
#onWillNavigate = async (e: CustomEvent) => {
183196
const newUrl = e.detail.url;
184197

src/packages/data-type/workspace/data-type-workspace.context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class UmbDataTypeWorkspaceContext
9292
setup: (_component, info) => {
9393
const parentEntityType = info.match.params.entityType;
9494
const parentUnique = info.match.params.parentUnique === 'null' ? null : info.match.params.parentUnique;
95-
this.create({ parent: { entityType: parentEntityType, unique: parentUnique } });
95+
this.createScaffold({ parent: { entityType: parentEntityType, unique: parentUnique } });
9696

9797
new UmbWorkspaceIsNewRedirectController(
9898
this,

src/packages/dictionary/workspace/dictionary-workspace.context.ts

Lines changed: 21 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,34 @@
11
import type { UmbDictionaryDetailModel } from '../types.js';
2-
import { UmbDictionaryDetailRepository } from '../repository/index.js';
2+
import { UMB_DICTIONARY_DETAIL_REPOSITORY_ALIAS, type UmbDictionaryDetailRepository } from '../repository/index.js';
3+
import { UMB_DICTIONARY_ENTITY_TYPE } from '../entity.js';
34
import { UmbDictionaryWorkspaceEditorElement } from './dictionary-workspace-editor.element.js';
5+
import { UMB_DICTIONARY_WORKSPACE_ALIAS } from './manifests.js';
46
import {
57
type UmbSubmittableWorkspaceContext,
6-
UmbSubmittableWorkspaceContextBase,
78
UmbWorkspaceIsNewRedirectController,
89
type UmbRoutableWorkspaceContext,
10+
UmbEntityDetailWorkspaceContextBase,
911
} from '@umbraco-cms/backoffice/workspace';
1012
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
11-
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
12-
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
13-
import {
14-
UmbRequestReloadChildrenOfEntityEvent,
15-
UmbRequestReloadStructureForEntityEvent,
16-
} from '@umbraco-cms/backoffice/entity-action';
1713

1814
export class UmbDictionaryWorkspaceContext
19-
extends UmbSubmittableWorkspaceContextBase<UmbDictionaryDetailModel>
15+
extends UmbEntityDetailWorkspaceContextBase<UmbDictionaryDetailModel, UmbDictionaryDetailRepository>
2016
implements UmbSubmittableWorkspaceContext, UmbRoutableWorkspaceContext
2117
{
22-
//
23-
public readonly detailRepository = new UmbDictionaryDetailRepository(this);
24-
25-
#parent = new UmbObjectState<{ entityType: string; unique: string | null } | undefined>(undefined);
26-
readonly parentUnique = this.#parent.asObservablePart((parent) => (parent ? parent.unique : undefined));
27-
readonly parentEntityType = this.#parent.asObservablePart((parent) => (parent ? parent.entityType : undefined));
18+
readonly data = this._data.current;
2819

29-
#data = new UmbObjectState<UmbDictionaryDetailModel | undefined>(undefined);
30-
readonly data = this.#data.asObservable();
20+
readonly unique = this._data.createObservablePartOfCurrent((data) => data?.unique);
21+
readonly entityType = this._data.createObservablePartOfCurrent((data) => data?.entityType);
3122

32-
readonly unique = this.#data.asObservablePart((data) => data?.unique);
33-
readonly entityType = this.#data.asObservablePart((data) => data?.entityType);
34-
35-
readonly name = this.#data.asObservablePart((data) => data?.name);
36-
readonly dictionary = this.#data.asObservablePart((data) => data);
23+
readonly name = this._data.createObservablePartOfCurrent((data) => data?.name);
24+
readonly dictionary = this._data.createObservablePartOfCurrent((data) => data);
3725

3826
constructor(host: UmbControllerHost) {
39-
super(host, 'Umb.Workspace.Dictionary');
27+
super(host, {
28+
workspaceAlias: UMB_DICTIONARY_WORKSPACE_ALIAS,
29+
entityType: UMB_DICTIONARY_ENTITY_TYPE,
30+
detailRepositoryAlias: UMB_DICTIONARY_DETAIL_REPOSITORY_ALIAS,
31+
});
4032

4133
this.routes.setRoutes([
4234
{
@@ -45,7 +37,7 @@ export class UmbDictionaryWorkspaceContext
4537
setup: async (_component, info) => {
4638
const parentEntityType = info.match.params.entityType;
4739
const parentUnique = info.match.params.parentUnique === 'null' ? null : info.match.params.parentUnique;
48-
this.create({ entityType: parentEntityType, unique: parentUnique });
40+
this.createScaffold({ parent: { entityType: parentEntityType, unique: parentUnique } });
4941

5042
new UmbWorkspaceIsNewRedirectController(
5143
this,
@@ -65,34 +57,18 @@ export class UmbDictionaryWorkspaceContext
6557
]);
6658
}
6759

68-
protected override resetState(): void {
69-
super.resetState();
70-
this.#data.setValue(undefined);
71-
}
72-
73-
getData() {
74-
return this.#data.getValue();
75-
}
76-
77-
getUnique() {
78-
return this.getData()?.unique;
79-
}
80-
81-
getEntityType() {
82-
return 'dictionary';
83-
}
84-
8560
setName(name: string) {
86-
this.#data.update({ name });
61+
this._data.updateCurrent({ name });
8762
}
8863

8964
setPropertyValue(isoCode: string, translation: string) {
90-
if (!this.#data.value) return;
65+
const currentData = this._data.getCurrent();
66+
if (!currentData) return;
9167

9268
// TODO: This can use some of our own methods, to make it simpler. see appendToFrozenArray()
9369
// update if the code already exists
9470
const updatedValue =
95-
this.#data.value.translations?.map((translationItem) => {
71+
currentData.translations?.map((translationItem) => {
9672
if (translationItem.isoCode === isoCode) {
9773
return { ...translationItem, translation };
9874
}
@@ -104,70 +80,7 @@ export class UmbDictionaryWorkspaceContext
10480
updatedValue?.push({ isoCode, translation });
10581
}
10682

107-
this.#data.setValue({ ...this.#data.value, translations: updatedValue });
108-
}
109-
110-
async load(unique: string) {
111-
this.resetState();
112-
const { data } = await this.detailRepository.requestByUnique(unique);
113-
if (data) {
114-
this.setIsNew(false);
115-
this.#data.setValue(data);
116-
}
117-
}
118-
119-
async create(parent: { entityType: string; unique: string | null }) {
120-
this.resetState();
121-
this.#parent.setValue(parent);
122-
const { data } = await this.detailRepository.createScaffold();
123-
if (!data) return;
124-
this.setIsNew(true);
125-
this.#data.setValue(data);
126-
}
127-
128-
async submit() {
129-
if (!this.#data.value) {
130-
throw new Error('No data to submit.');
131-
}
132-
if (!this.#data.value.unique) {
133-
throw new Error('No unique value to submit.');
134-
}
135-
136-
if (this.getIsNew()) {
137-
const parent = this.#parent.getValue();
138-
if (!parent) {
139-
throw new Error('Parent is not set');
140-
}
141-
const { error } = await this.detailRepository.create(this.#data.value, parent.unique);
142-
if (error) {
143-
throw new Error(error.message);
144-
}
145-
146-
// TODO: this might not be the right place to alert the tree, but it works for now
147-
const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
148-
const event = new UmbRequestReloadChildrenOfEntityEvent({
149-
entityType: parent.entityType,
150-
unique: parent.unique,
151-
});
152-
eventContext.dispatchEvent(event);
153-
154-
this.setIsNew(false);
155-
} else {
156-
await this.detailRepository.save(this.#data.value);
157-
158-
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
159-
const event = new UmbRequestReloadStructureForEntityEvent({
160-
unique: this.getUnique()!,
161-
entityType: this.getEntityType(),
162-
});
163-
164-
actionEventContext.dispatchEvent(event);
165-
}
166-
}
167-
168-
public override destroy(): void {
169-
this.#data.destroy();
170-
super.destroy();
83+
this._data.setCurrent({ ...currentData, translations: updatedValue });
17184
}
17285
}
17386

src/packages/language/workspace/language/language-workspace.context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class UmbLanguageWorkspaceContext
3434
path: 'create',
3535
component: UmbLanguageWorkspaceEditorElement,
3636
setup: async () => {
37-
this.create({ parent: { entityType: UMB_LANGUAGE_ROOT_ENTITY_TYPE, unique: null } });
37+
this.createScaffold({ parent: { entityType: UMB_LANGUAGE_ROOT_ENTITY_TYPE, unique: null } });
3838

3939
new UmbWorkspaceIsNewRedirectController(
4040
this,

0 commit comments

Comments
 (0)