Skip to content

Commit 595e4ed

Browse files
V16 RC: Documents show "Not found" when switching between variant and invariant views, and other edge cases (#19425)
* fix: add a catcher to most `asPromise` for stores to prevent cascading errors * fix: remove conditional instances - they should be able to be undefined * fix: check for missing store and extract UmbProblemDetails * fix: only append data if no error * fix: adds error handling to missing stores and to extract the ProblemDetails object * revert commit * fix: ignore errors completely instead of unsetting stores * revert commit * chore: cleanup imports * fix: do not unset store * stop observation in a proper way * stop observation of for document-user-permissions * check for manager twice * save action * save action optional * simplify init for detail repostiory * fix routes * adjusting more not found routes * fix structure manager clean up --------- Co-authored-by: Niels Lyngsø <[email protected]>
1 parent 434189e commit 595e4ed

File tree

25 files changed

+222
-129
lines changed

25 files changed

+222
-129
lines changed

src/Umbraco.Web.UI.Client/src/apps/backoffice/backoffice.context.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export class UmbBackofficeContext extends UmbContextBase {
7777
}
7878

7979
public async serverUpgradeCheck() {
80-
const version = await this.observe(this.version).asPromise();
80+
const version = await this.observe(this.version)
81+
.asPromise()
82+
.catch(() => null);
83+
if (!version) return null;
8184
const repository = new UmbSysinfoRepository(this);
8285
return repository.serverUpgradeCheck(version);
8386
}

src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entry.context.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,18 +548,27 @@ export abstract class UmbBlockEntryContext<
548548
abstract _gotContentType(contentType: UmbContentTypeModel | undefined): void;
549549

550550
async #observeVariantId() {
551-
if (!this._manager) return;
551+
if (!this._manager) {
552+
this.removeUmbControllerByAlias('observeVariantId');
553+
return;
554+
}
552555
await this.#contentStructurePromise;
553556
if (!this.#contentStructure) {
554557
throw new Error('No contentStructure found');
555558
}
556559

560+
if (!this._manager) {
561+
// The manager maybe got removed while we awaited the promise above.
562+
this.removeUmbControllerByAlias('observeVariantId');
563+
return;
564+
}
565+
557566
// observe variantId:
558567
this.observe(
559568
observeMultiple([
560569
this._manager.variantId,
561-
this.#contentStructure?.ownerContentTypeObservablePart((x) => x?.variesByCulture),
562-
this.#contentStructure?.ownerContentTypeObservablePart((x) => x?.variesBySegment),
570+
this.#contentStructure.ownerContentTypeObservablePart((x) => x?.variesByCulture),
571+
this.#contentStructure.ownerContentTypeObservablePart((x) => x?.variesBySegment),
563572
]),
564573
([variantId, variesByCulture, variesBySegment]) => {
565574
if (!variantId || variesByCulture === undefined || variesBySegment === undefined) return;

src/Umbraco.Web.UI.Client/src/packages/content/content-type/structure/content-type-structure-manager.class.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export class UmbContentTypeStructureManager<
182182
return { data: this.getOwnerContentType(), asObservable: () => this.ownerContentType };
183183
}
184184
await this.#initRepository;
185-
this.#clear();
185+
this.clear();
186186
this.#ownerContentTypeUnique = unique;
187187
if (!unique) {
188188
this.#initRejection?.(`Content Type structure manager could not load: ${unique}`);
@@ -199,7 +199,7 @@ export class UmbContentTypeStructureManager<
199199

200200
public async createScaffold(preset?: Partial<T>): Promise<UmbRepositoryResponse<T>> {
201201
await this.#initRepository;
202-
this.#clear();
202+
this.clear();
203203

204204
const repsonse = await this.#repository!.createScaffold(preset);
205205
const { data } = repsonse;
@@ -827,7 +827,7 @@ export class UmbContentTypeStructureManager<
827827
.filter(UmbFilterDuplicateStrings);
828828
}
829829

830-
#clear() {
830+
public clear() {
831831
this.#contentTypeObservers.forEach((observer) => observer.destroy());
832832
this.#contentTypeObservers = [];
833833
this.#repoManager?.clear();

src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/views/design/content-type-design-editor.element.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,16 @@ export class UmbContentTypeDesignEditorElement extends UmbLitElement implements
227227
this.#currentTabComponent = undefined;
228228
},
229229
});
230+
} else {
231+
routes.push({
232+
path: `**`,
233+
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
234+
setup: () => {
235+
this.#currentTabComponent = undefined;
236+
},
237+
});
230238
}
231239

232-
routes.push({
233-
path: `**`,
234-
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
235-
setup: () => {
236-
this.#currentTabComponent = undefined;
237-
},
238-
});
239-
240240
this._routes = routes;
241241

242242
// If we have a active tab, then we want to make sure its up to date with latest tab id, as an already active route is not getting its setup method triggered again [NL]

src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/content-detail-workspace-base.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,7 @@ export abstract class UmbContentDetailWorkspaceContextBase<
982982

983983
override resetState() {
984984
super.resetState();
985+
this.structure.clear();
985986
this.readOnlyGuard.clearRules();
986987
this.propertyViewGuard.clearRules();
987988
this.propertyWriteGuard.clearRules();

src/Umbraco.Web.UI.Client/src/packages/content/property-type/workspace/property-type-workspace.context.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ export class UmbPropertyTypeWorkspaceContext
7272
this.#contentTypeContext = context;
7373
})
7474
.skipHost()
75-
.asPromise({ preventTimeout: true });
75+
.asPromise({ preventTimeout: true })
76+
.catch(() => {
77+
// If the context is not available, we can assume that the context is not available.
78+
this.#contentTypeContext = undefined;
79+
});
7680

7781
this.routes.setRoutes([
7882
{

src/Umbraco.Web.UI.Client/src/packages/core/collection/collection-view.manager.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ export class UmbCollectionViewManager extends UmbControllerBase {
101101
this.setCurrentView(fallbackView);
102102
},
103103
});
104-
}
105104

106-
routes.push({
107-
path: `**`,
108-
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
109-
});
105+
routes.push({
106+
path: `**`,
107+
component: async () => (await import('@umbraco-cms/backoffice/router')).UmbRouteNotFoundElement,
108+
});
109+
}
110110
}
111111

112112
this.#routes.setValue(routes);

src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository-base.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,12 @@ export abstract class UmbDetailRepositoryBase<
3333
this.detailDataSource = new detailSource(host) as UmbDetailDataSourceType;
3434

3535
// TODO: ideally no preventTimeouts here.. [NL]
36-
this.#init = Promise.all([
37-
this.consumeContext(detailStoreContextAlias, (instance) => {
38-
if (instance) {
39-
this.#detailStore = instance;
40-
}
41-
}).asPromise({ preventTimeout: true }),
42-
]);
36+
this.#init = this.consumeContext(detailStoreContextAlias, (instance) => {
37+
this.#detailStore = instance;
38+
})
39+
.asPromise({ preventTimeout: true })
40+
// Ignore the error, we can assume that the flow was stopped (asPromise failed), but it does not mean that the consumption was not successful.
41+
.catch(() => undefined);
4342
}
4443

4544
/**

src/Umbraco.Web.UI.Client/src/packages/core/repository/item/item-repository-base.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { UmbItemRepository } from './item-repository.interface.js';
44
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
55
import type { UmbItemStore } from '@umbraco-cms/backoffice/store';
66
import type { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
7+
import { of } from '@umbraco-cms/backoffice/external/rxjs';
78

89
export class UmbItemRepositoryBase<ItemType extends { unique: string }>
910
extends UmbRepositoryBase
@@ -22,10 +23,11 @@ export class UmbItemRepositoryBase<ItemType extends { unique: string }>
2223
this.#itemSource = new itemSource(host);
2324

2425
this._init = this.consumeContext(itemStoreContextAlias, (instance) => {
25-
if (instance) {
26-
this._itemStore = instance as UmbItemStore<ItemType>;
27-
}
28-
}).asPromise({ preventTimeout: true });
26+
this._itemStore = instance;
27+
})
28+
.asPromise({ preventTimeout: true })
29+
// Ignore the error, we can assume that the flow was stopped (asPromise failed), but it does not mean that the consumption was not successful.
30+
.catch(() => undefined);
2931
}
3032

3133
/**
@@ -42,18 +44,19 @@ export class UmbItemRepositoryBase<ItemType extends { unique: string }>
4244
return {};
4345
}
4446

45-
const { data, error: _error } = await this.#itemSource.getItems(uniques);
47+
const { data, error } = await this.#itemSource.getItems(uniques);
4648

4749
if (!this._itemStore) {
4850
// If store is gone, then we are most likely in a disassembled state.
4951
return {};
5052
}
51-
const error: any = _error;
53+
5254
if (data) {
53-
this._itemStore!.appendItems(data);
55+
this._itemStore.appendItems(data);
5456
}
5557

56-
return { data, error, asObservable: () => this._itemStore!.items(uniques) };
58+
// TODO: Fix the type of error, it should be UmbApiError, but currently it is any.
59+
return { data, error: error as any, asObservable: () => this._itemStore!.items(uniques) };
5760
}
5861

5962
/**
@@ -68,6 +71,12 @@ export class UmbItemRepositoryBase<ItemType extends { unique: string }>
6871
} catch {
6972
return undefined;
7073
}
71-
return this._itemStore!.items(uniques);
74+
75+
if (!this._itemStore) {
76+
// If store is gone, then we are most likely in a disassembled state.
77+
return of([]);
78+
}
79+
80+
return this._itemStore.items(uniques);
7281
}
7382
}

src/Umbraco.Web.UI.Client/src/packages/core/tree/data/tree-repository-base.ts

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
1212
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
1313
import type { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
1414
import type { UmbProblemDetails } from '@umbraco-cms/backoffice/resources';
15+
import { of } from '@umbraco-cms/backoffice/external/rxjs';
1516

1617
/**
1718
* Base class for a tree repository.
@@ -61,10 +62,11 @@ export abstract class UmbTreeRepositoryBase<
6162
this._treeSource = new treeSourceConstructor(this);
6263

6364
this._init = this.consumeContext(treeStoreContextAlias, (instance) => {
64-
if (instance) {
65-
this._treeStore = instance;
66-
}
67-
}).asPromise({ preventTimeout: true });
65+
this._treeStore = instance;
66+
})
67+
.asPromise({ preventTimeout: true })
68+
// Ignore the error, we can assume that the flow was stopped (asPromise failed), but it does not mean that the consumption was not successful.
69+
.catch(() => undefined);
6870
}
6971

7072
/**
@@ -84,16 +86,18 @@ export abstract class UmbTreeRepositoryBase<
8486
await this._init;
8587

8688
const { data, error } = await this._treeSource.getRootItems(args);
89+
8790
if (!this._treeStore) {
8891
// If the tree store is not available, then we most likely are in a destructed setting.
8992
return {};
9093
}
94+
9195
if (data) {
92-
this._treeStore?.appendItems(data.items);
96+
this._treeStore.appendItems(data.items);
9397
}
9498

95-
// TODO: Notice we are casting the error here, is that right?
96-
return { data, error: error as unknown as UmbProblemDetails, asObservable: () => this._treeStore!.rootItems };
99+
// TODO: Fix the type of error, it should be UmbApiError, but currently it is any.
100+
return { data, error: error as any, asObservable: () => this._treeStore!.rootItems };
97101
}
98102

99103
/**
@@ -109,13 +113,19 @@ export abstract class UmbTreeRepositoryBase<
109113
if (args.parent.entityType === null) throw new Error('Parent entity type is missing');
110114
await this._init;
111115

112-
const { data, error: _error } = await this._treeSource.getChildrenOf(args);
113-
const error: any = _error;
116+
const { data, error } = await this._treeSource.getChildrenOf(args);
117+
118+
if (!this._treeStore) {
119+
// If the tree store is not available, then we most likely are in a destructed setting.
120+
return {};
121+
}
122+
114123
if (data) {
115-
this._treeStore?.appendItems(data.items);
124+
this._treeStore.appendItems(data.items);
116125
}
117126

118-
return { data, error, asObservable: () => this._treeStore!.childrenOf(args.parent.unique) };
127+
// TODO: Fix the type of error, it should be UmbApiError, but currently it is any.
128+
return { data, error: error as any, asObservable: () => this._treeStore!.childrenOf(args.parent.unique) };
119129
}
120130

121131
/**
@@ -128,10 +138,11 @@ export abstract class UmbTreeRepositoryBase<
128138
if (args.treeItem.unique === undefined) throw new Error('Descendant unique is missing');
129139
await this._init;
130140

131-
const { data, error: _error } = await this._treeSource.getAncestorsOf(args);
132-
const error: any = _error;
141+
const { data, error } = await this._treeSource.getAncestorsOf(args);
142+
133143
// TODO: implement observable for ancestor items in the store
134-
return { data, error };
144+
// TODO: Fix the type of error, it should be UmbApiError, but currently it is any.
145+
return { data, error: error as any };
135146
}
136147

137148
/**
@@ -141,7 +152,13 @@ export abstract class UmbTreeRepositoryBase<
141152
*/
142153
async rootTreeItems() {
143154
await this._init;
144-
return this._treeStore!.rootItems;
155+
156+
if (!this._treeStore) {
157+
// If the tree store is not available, then we most likely are in a destructed setting.
158+
return of([]);
159+
}
160+
161+
return this._treeStore.rootItems;
145162
}
146163

147164
/**
@@ -153,6 +170,12 @@ export abstract class UmbTreeRepositoryBase<
153170
async treeItemsOf(parentUnique: string | null) {
154171
if (parentUnique === undefined) throw new Error('Parent unique is missing');
155172
await this._init;
156-
return this._treeStore!.childrenOf(parentUnique);
173+
174+
if (!this._treeStore) {
175+
// If the tree store is not available, then we most likely are in a destructed setting.
176+
return of([]);
177+
}
178+
179+
return this._treeStore.childrenOf(parentUnique);
157180
}
158181
}

0 commit comments

Comments
 (0)