Fix: Add "Not Found" empty state to detail workspaces (#17489)

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com>
This commit is contained in:
Mads Rasmussen
2024-11-19 09:14:41 +01:00
committed by GitHub
parent 7cc8f844f7
commit 310ccdc011
29 changed files with 271 additions and 167 deletions

View File

@@ -359,6 +359,16 @@ export default {
blueprintDescription:
'A Document Blueprint is predefined content that an editor can select to use as the\n basis for creating new content\n ',
},
entityDetail: {
notFoundTitle: (entityType: string) => {
const entityName = entityType ?? 'Item';
return `${entityName} not found`;
},
notFoundDescription: (entityType: string) => {
const entityName = entityType ?? 'item';
return `The requested ${entityName} could not be found. Please check the URL and try again.`;
},
},
media: {
clickToUpload: 'Click to upload',
orClickHereToUpload: 'or click here to choose files',

View File

@@ -37,6 +37,9 @@ export class UmbBodyLayoutElement extends LitElement {
@property({ type: Boolean, reflect: true, attribute: 'header-transparent' })
public headerTransparent = false;
@property({ type: Boolean })
loading = false;
@state()
private _headerSlotHasChildren = false;
@@ -116,6 +119,7 @@ export class UmbBodyLayoutElement extends LitElement {
<!-- This div should be changed for the uui-scroll-container when it gets updated -->
<div id="main">
${this.loading ? html`<uui-loader-bar></uui-loader-bar>` : nothing}
<slot></slot>
</div>

View File

@@ -32,6 +32,9 @@ export class UmbWorkspaceEditorElement extends UmbLitElement {
@property({ attribute: 'back-path' })
public backPath?: string;
@property({ type: Boolean })
public loading = false;
@state()
private _workspaceViews: Array<ManifestWorkspaceView> = [];
@@ -83,7 +86,7 @@ export class UmbWorkspaceEditorElement extends UmbLitElement {
override render() {
return html`
<umb-body-layout main-no-padding .headline=${this.headline}>
<umb-body-layout main-no-padding .headline=${this.headline} ?loading=${this.loading}>
${this.#renderBackButton()}
<slot name="header" slot="header"></slot>
${this.#renderViews()}

View File

@@ -26,16 +26,15 @@ export class UmbWorkspaceEntityActionMenuElement extends UmbLitElement {
this.consumeContext(UMB_ENTITY_WORKSPACE_CONTEXT, (context) => {
this._workspaceContext = context;
this._observeInfo();
this.observe(this._workspaceContext.unique, (unique) => {
this._unique = unique;
// TODO: the context does not have an observable for the entity type, so we need to use the
// getEntityType method until we can add an observable for it.
this._entityType = this._workspaceContext?.getEntityType();
});
});
}
private _observeInfo() {
if (!this._workspaceContext) return;
this._unique = this._workspaceContext.getUnique();
this._entityType = this._workspaceContext.getEntityType();
}
#onActionExecuted(event: UmbActionExecutedEvent) {
event.stopPropagation();

View File

@@ -1,5 +1,6 @@
import { UmbSubmittableWorkspaceContextBase } from '../submittable/index.js';
import { UmbEntityWorkspaceDataManager } from '../entity/entity-workspace-data-manager.js';
import type { UmbEntityDetailWorkspaceContextArgs, UmbEntityDetailWorkspaceContextCreateArgs } from './types.js';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbEntityContext, type UmbEntityModel, type UmbEntityUnique } from '@umbraco-cms/backoffice/entity';
@@ -12,29 +13,19 @@ import {
import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api';
import { umbExtensionsRegistry, type ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
import { UmbStateManager } from '@umbraco-cms/backoffice/utils';
export interface UmbEntityDetailWorkspaceContextArgs {
entityType: string;
workspaceAlias: string;
detailRepositoryAlias: string;
}
/**
* @deprecated Use UmbEntityDetailWorkspaceContextArgs instead
*/
export type UmbEntityWorkspaceContextArgs = UmbEntityDetailWorkspaceContextArgs;
export interface UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> {
parent: UmbEntityModel;
preset?: Partial<DetailModelType>;
}
const LOADING_STATE_UNIQUE = 'umbLoadingEntityDetail';
export abstract class UmbEntityDetailWorkspaceContextBase<
DetailModelType extends UmbEntityModel,
DetailModelType extends UmbEntityModel = UmbEntityModel,
DetailRepositoryType extends UmbDetailRepository<DetailModelType> = UmbDetailRepository<DetailModelType>,
CreateArgsType extends
UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> = UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType>,
> extends UmbSubmittableWorkspaceContextBase<DetailModelType> {
// Just for context token safety:
public readonly IS_ENTITY_DETAIL_WORKSPACE_CONTEXT = true;
/**
* @description Data manager for the workspace.
* @protected
@@ -42,15 +33,16 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
*/
protected readonly _data = new UmbEntityWorkspaceDataManager<DetailModelType>(this);
public readonly data = this._data.current;
protected _getDataPromise?: Promise<any>;
protected _detailRepository?: DetailRepositoryType;
#entityContext = new UmbEntityContext(this);
public readonly entityType = this.#entityContext.entityType;
public readonly unique = this.#entityContext.unique;
public readonly data = this._data.current;
public readonly loading = new UmbStateManager(this);
protected _getDataPromise?: Promise<any>;
protected _detailRepository?: DetailRepositoryType;
#parent = new UmbObjectState<{ entityType: string; unique: UmbEntityUnique } | undefined>(undefined);
public readonly parentUnique = this.#parent.asObservablePart((parent) => (parent ? parent.unique : undefined));
public readonly parentEntityType = this.#parent.asObservablePart((parent) =>
@@ -131,6 +123,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
async load(unique: string) {
this.#entityContext.setUnique(unique);
this.loading.addState({ unique: LOADING_STATE_UNIQUE, message: `Loading ${this.getEntityType()} Details` });
await this.#init;
this.resetState();
this._getDataPromise = this._detailRepository!.requestByUnique(unique);
@@ -142,8 +135,15 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
this._data.setPersisted(data);
this._data.setCurrent(data);
this.setIsNew(false);
this.observe(
response.asObservable(),
(entity) => this.#onDetailStoreChange(entity),
'umbEntityDetailTypeStoreObserver',
);
}
this.loading.removeState(LOADING_STATE_UNIQUE);
return response;
}
@@ -166,6 +166,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
* @returns { Promise<any> | undefined } The data of the scaffold.
*/
public async createScaffold(args: CreateArgsType) {
this.loading.addState({ unique: LOADING_STATE_UNIQUE, message: `Creating ${this.getEntityType()} scaffold` });
await this.#init;
this.resetState();
this.setParent(args.parent);
@@ -173,17 +174,20 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
const request = this._detailRepository!.createScaffold(args.preset);
this._getDataPromise = request;
let { data } = await request;
if (!data) return undefined;
this.#entityContext.setUnique(data.unique);
if (data) {
this.#entityContext.setUnique(data.unique);
if (this.modalContext) {
data = { ...data, ...this.modalContext.data.preset };
if (this.modalContext) {
data = { ...data, ...this.modalContext.data.preset };
}
this.setIsNew(true);
this._data.setPersisted(data);
this._data.setCurrent(data);
}
this.setIsNew(true);
this._data.setPersisted(data);
this._data.setCurrent(data);
this.loading.removeState(LOADING_STATE_UNIQUE);
return data;
}
@@ -284,9 +288,9 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
}
if (this._checkWillNavigateAway(newUrl) && this._getHasUnpersistedChanges()) {
/* Since ours modals are async while events are synchronous, we need to prevent the default behavior of the event, even if the modal hasnt been resolved yet.
Once the modal is resolved (the user accepted to discard the changes and navigate away from the route), we will push a new history state.
This push will make the "willchangestate" event happen again and due to this somewhat "backward" behavior,
/* Since ours modals are async while events are synchronous, we need to prevent the default behavior of the event, even if the modal hasnt been resolved yet.
Once the modal is resolved (the user accepted to discard the changes and navigate away from the route), we will push a new history state.
This push will make the "willchangestate" event happen again and due to this somewhat "backward" behavior,
we set an "allowNavigateAway"-flag to prevent the "discard-changes" functionality from running in a loop.*/
e.preventDefault();
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
@@ -342,6 +346,12 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
);
}
#onDetailStoreChange(entity: DetailModelType | undefined) {
if (!entity) {
this._data.clear();
}
}
public override destroy(): void {
window.removeEventListener('willchangestate', this.#onWillNavigate);
this._detailRepository?.destroy();

View File

@@ -0,0 +1,12 @@
import type { UmbWorkspaceContext } from '../workspace-context.interface.js';
import type { UmbEntityDetailWorkspaceContextBase } from './entity-detail-workspace-base.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export const UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT = new UmbContextToken<
UmbWorkspaceContext,
UmbEntityDetailWorkspaceContextBase
>(
'UmbWorkspaceContext',
undefined,
(context): context is UmbEntityDetailWorkspaceContextBase => (context as any).IS_ENTITY_DETAIL_WORKSPACE_CONTEXT,
);

View File

@@ -0,0 +1,50 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-entity-detail-not-found')
export class UmbEntityDetailNotFoundElement extends UmbLitElement {
@property({ type: String, attribute: 'entity-type' })
entityType = '';
override render() {
return html`
<div class="uui-text">
<h4>${this.localize.term('entityDetail_notFoundTitle', this.entityType)}</h4>
${this.localize.term('entityDetail_notFoundDescription', this.entityType)}
</div>
`;
}
static override styles = [
UmbTextStyles,
css`
:host {
display: block;
width: 100%;
height: 100%;
min-width: 0;
}
:host > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
}
@keyframes fadeIn {
100% {
opacity: 100%;
}
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'umb-entity-detail-not-found': UmbEntityDetailNotFoundElement;
}
}

View File

@@ -0,0 +1,77 @@
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT } from '../entity-detail-workspace.context-token.js';
import { css, customElement, html, ifDefined, nothing, property, state } from '@umbraco-cms/backoffice/external/lit';
@customElement('umb-entity-detail-workspace-editor')
export class UmbEntityDetailWorkspaceEditorElement extends UmbLitElement {
@property({ attribute: 'back-path' })
public backPath?: string;
@state()
private _entityType?: string;
@state()
private _isLoading = false;
@state()
private _exists = false;
@state()
private _isNew? = false;
#context?: typeof UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT.TYPE;
constructor() {
super();
this.consumeContext(UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT, (context) => {
this.#context = context;
this.observe(this.#context?.entityType, (entityType) => (this._entityType = entityType));
this.observe(this.#context?.loading.isOn, (isLoading) => (this._isLoading = isLoading));
this.observe(this.#context?.data, (data) => (this._exists = !!data));
this.observe(this.#context?.isNew, (isNew) => (this._isNew = isNew));
});
}
protected override render() {
return html` ${!this._exists && !this._isLoading
? html`<umb-entity-detail-not-found entity-type=${ifDefined(this._entityType)}></umb-entity-detail-not-found>`
: nothing}
<!-- TODO: It is currently on purpose that the workspace editor is always in the DOM, even when it doesn't have data.
We currently rely on the entity actions to be available to execute, and we ran into an issue when the entity got deleted; then the DOM got cleared, and the delete action couldn't complete.
We need to look into loading the entity actions in the workspace context instead so we don't rely on the DOM.
-->
<umb-workspace-editor
?loading=${this._isLoading}
.backPath=${this.backPath}
class="${this._exists === false ? 'hide' : ''}">
<slot name="header" slot="header"></slot>
${this.#renderEntityActions()}
<slot></slot>
</umb-workspace-editor>`;
}
#renderEntityActions() {
if (this._isNew) return nothing;
return html`<umb-workspace-entity-action-menu slot="action-menu"></umb-workspace-entity-action-menu>`;
}
static override styles = [
css`
umb-workspace-editor {
visibility: visible;
}
umb-workspace-editor.hide {
visibility: hidden;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'umb-entity-detail-workspace-editor': UmbEntityDetailWorkspaceEditorElement;
}
}

View File

@@ -0,0 +1,5 @@
import './entity-detail-not-found.element.js';
import './entity-detail-workspace-editor.element.js';
export * from './entity-detail-not-found.element.js';
export * from './entity-detail-workspace-editor.element.js';

View File

@@ -1 +1,5 @@
import './global-components/index.js';
export * from './entity-detail-workspace-base.js';
export * from './global-components/index.js';
export type * from './types.js';

View File

@@ -0,0 +1,17 @@
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
export interface UmbEntityDetailWorkspaceContextArgs {
entityType: string;
workspaceAlias: string;
detailRepositoryAlias: string;
}
/**
* @deprecated Use UmbEntityDetailWorkspaceContextArgs instead
*/
export type UmbEntityWorkspaceContextArgs = UmbEntityDetailWorkspaceContextArgs;
export interface UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> {
parent: UmbEntityModel;
preset?: Partial<DetailModelType>;
}

View File

@@ -1,3 +1,5 @@
import './entity-detail/global-components/index.js';
export * from './components/index.js';
export * from './conditions/const.js';
export * from './contexts/index.js';
@@ -15,3 +17,4 @@ export * from './workspace.context-token.js';
export * from './workspace.element.js';
export type * from './conditions/index.js';
export type * from './types.js';
export * from './entity-detail/global-components/index.js';

View File

@@ -3,4 +3,6 @@ import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export interface UmbWorkspaceContext extends UmbApi {
readonly workspaceAlias: string;
getEntityType(): string;
// TODO: Consider if its more right to make a new interface for UmbEntityWorkspaceContext, cause this on might be intended for the extension type Workspace Context
// TODO: add entityType observable
}

View File

@@ -17,9 +17,9 @@ export class UmbDataTypeWorkspaceEditorElement extends UmbLitElement {
override render() {
return html`
<umb-workspace-editor>
<umb-entity-detail-workspace-editor>
<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}

View File

@@ -114,19 +114,6 @@ export class UmbDataTypeWorkspaceContext
]);
}
override async load(unique: string) {
const response = await super.load(unique);
this.observe(response.asObservable?.(), (entity) => this.#onStoreChange(entity), 'umbDataTypeStoreObserver');
return response;
}
#onStoreChange(entity: EntityType | undefined) {
if (!entity) {
//TODO: This solution is alright for now. But reconsider when we introduce signal-r
history.pushState(null, '', 'section/settings/workspace/data-type-root');
}
}
override resetState() {
super.resetState();
this.#propertyEditorSchemaSettingsProperties = [];

View File

@@ -6,9 +6,9 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
export class UmbDictionaryWorkspaceEditorElement extends UmbLitElement {
override render() {
return html`
<umb-workspace-editor back-path=${UMB_DICTIONARY_OVERVIEW_DASHBOARD_PATH}>
<umb-entity-detail-workspace-editor .backPath=${UMB_DICTIONARY_OVERVIEW_DASHBOARD_PATH}>
<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}
}

View File

@@ -0,0 +1,8 @@
import { UMB_SETTINGS_SECTION_PATHNAME } from '@umbraco-cms/backoffice/settings';
import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace';
import { UMB_LANGUAGE_ROOT_ENTITY_TYPE } from '../../entity.js';
export const UMB_LANGUAGE_ROOT_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({
sectionName: UMB_SETTINGS_SECTION_PATHNAME,
entityType: UMB_LANGUAGE_ROOT_ENTITY_TYPE,
});

View File

@@ -2,6 +2,7 @@ import { UMB_LANGUAGE_WORKSPACE_CONTEXT } from './language-workspace.context-tok
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UMB_LANGUAGE_ROOT_WORKSPACE_PATH } from '../language-root/paths.js';
@customElement('umb-language-workspace-editor')
export class UmbLanguageWorkspaceEditorElement extends UmbLitElement {
#workspaceContext?: typeof UMB_LANGUAGE_WORKSPACE_CONTEXT.TYPE;
@@ -19,11 +20,11 @@ export class UmbLanguageWorkspaceEditorElement extends UmbLitElement {
}
override render() {
return html`<umb-workspace-editor back-path="section/settings/workspace/language-root">
return html`<umb-entity-detail-workspace-editor .backPath=${UMB_LANGUAGE_ROOT_WORKSPACE_PATH}>
${this._isNew
? html`<h3 slot="header">Add language</h3>`
: html`<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>`}
</umb-workspace-editor>`;
: html`<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable> `}
</umb-entity-detail-workspace-editor>`;
}
static override styles = [UmbTextStyles];

View File

@@ -1,40 +1,15 @@
import { UMB_MEMBER_GROUP_ROOT_WORKSPACE_PATH } from '../../paths.js';
import { UMB_MEMBER_GROUP_WORKSPACE_CONTEXT } from './member-group-workspace.context-token.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('umb-member-group-workspace-editor')
export class UmbMemberGroupWorkspaceEditorElement extends UmbLitElement {
@state()
private _unique?: string;
#workspaceContext?: typeof UMB_MEMBER_GROUP_WORKSPACE_CONTEXT.TYPE;
constructor() {
super();
this.consumeContext(UMB_MEMBER_GROUP_WORKSPACE_CONTEXT, (workspaceContext) => {
this.#workspaceContext = workspaceContext;
if (!this.#workspaceContext) return;
this.observe(this.#workspaceContext.unique, (unique) => (this._unique = unique ?? undefined));
});
}
#renderActions() {
// Actions only works if we have a valid unique.
if (!this._unique || this.#workspaceContext?.getIsNew()) return nothing;
return html`<umb-workspace-entity-action-menu slot="action-menu"></umb-workspace-entity-action-menu>`;
}
override render() {
return html`
<umb-workspace-editor back-path=${UMB_MEMBER_GROUP_ROOT_WORKSPACE_PATH}>
<umb-entity-detail-workspace-editor .backPath=${UMB_MEMBER_GROUP_ROOT_WORKSPACE_PATH}>
<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>
${this.#renderActions()}
<umb-workspace-entity-action-menu slot="action-menu"></umb-workspace-entity-action-menu>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}

View File

@@ -50,24 +50,6 @@ export class UmbMemberGroupWorkspaceContext
]);
}
override async load(unique: string) {
const response = await super.load(unique);
this.observe(
response.asObservable?.(),
(memberGroup) => this.#onMemberGroupStoreChange(memberGroup),
'umbMemberGroupStoreObserver',
);
return response;
}
#onMemberGroupStoreChange(memberGroup: UmbMemberGroupDetailModel | undefined) {
if (!memberGroup) {
history.pushState(null, '', 'section/member-management/view/member-groups');
}
}
getName() {
return this._data.getCurrent()?.name;
}

View File

@@ -77,9 +77,8 @@ export class UmbPartialViewWorkspaceEditorElement extends UmbLitElement {
}
override render() {
if (this._isNew === undefined) return;
return html`
<umb-workspace-editor>
<umb-entity-detail-workspace-editor>
<div id="workspace-header" slot="header">
<uui-input
placeholder=${this.localize.term('placeholders_entername')}
@@ -103,7 +102,7 @@ export class UmbPartialViewWorkspaceEditorElement extends UmbLitElement {
</div>
${this.#renderCodeEditor()}
</uui-box>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}

View File

@@ -96,20 +96,6 @@ export class UmbPartialViewWorkspaceContext
this._data.updateCurrent({ content: value });
}
override async load(unique: string) {
const response = await super.load(unique);
this.observe(response.asObservable?.(), (data) => this.#onDetailStoreChanges(data), 'umbDetailStoreObserver');
return response;
}
#onDetailStoreChanges(data: UmbPartialViewDetailModel | undefined) {
// Data is removed from the store
// TODO: revisit. We need to handle what should happen when the data is removed from the store
if (data === undefined) {
this._data.clear();
}
}
override async createScaffold(args: UmbPartialViewWorkspaceContextCreateArgs) {
let snippetContent = '';

View File

@@ -52,9 +52,8 @@ export class UmbScriptWorkspaceEditorElement extends UmbLitElement {
}
override render() {
if (this._isNew === undefined) return;
return html`
<umb-workspace-editor>
<umb-entity-detail-workspace-editor>
<div id="workspace-header" slot="header">
<uui-input
placeholder=${this.localize.term('placeholders_entername')}
@@ -70,7 +69,7 @@ export class UmbScriptWorkspaceEditorElement extends UmbLitElement {
<div slot="header"></div>
${this.#renderCodeEditor()}
</uui-box>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}

View File

@@ -70,26 +70,6 @@ export class UmbScriptWorkspaceContext
public setContent(value: string) {
this._data.updateCurrent({ content: value });
}
/**
* @description load the script
* @param unique The unique identifier of the script
* @returns {Promise<void>}
* @memberof UmbScriptWorkspaceContext
*/
public override async load(unique: string) {
const response = await super.load(unique);
this.observe(response.asObservable?.(), (data) => this.#onDetailStoreChanges(data), 'umbDetailStoreObserver');
return response;
}
#onDetailStoreChanges(data: UmbScriptDetailModel | undefined) {
// Data is removed from the store
// TODO: revisit. We need to handle what should happen when the data is removed from the store
if (data === undefined) {
this._data.clear();
}
}
}
export { UmbScriptWorkspaceContext as api };

View File

@@ -160,7 +160,7 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
override render() {
// TODO: add correct UI elements
return html`
<umb-workspace-editor>
<umb-entity-detail-workspace-editor>
<umb-input-with-alias
slot="header"
id="name"
@@ -195,7 +195,7 @@ export class UmbTemplateWorkspaceEditorElement extends UmbLitElement {
${this.#renderCodeEditor()}
</uui-box>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}

View File

@@ -168,12 +168,10 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
}
override render() {
if (!this._unique) return nothing;
return html`
<umb-workspace-editor class="uui-text" back-path=${UMB_USER_GROUP_ROOT_WORKSPACE_PATH}>
<umb-entity-detail-workspace-editor class="uui-text" back-path=${UMB_USER_GROUP_ROOT_WORKSPACE_PATH}>
${this.#renderHeader()} ${this.#renderMain()}
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}
@@ -219,8 +217,6 @@ export class UmbUserGroupWorkspaceEditorElement extends UmbLitElement {
${umbFocus()}>
</umb-input-with-alias>
</div>
<umb-workspace-entity-action-menu slot="action-menu"></umb-workspace-entity-action-menu>
`;
}

View File

@@ -35,24 +35,19 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement {
}
override render() {
if (!this._user) return html`User not found`;
return html`
<umb-workspace-editor class="uui-text" back-path=${UMB_USER_ROOT_WORKSPACE_PATH}>
<umb-entity-detail-workspace-editor class="uui-text" .backPath=${UMB_USER_ROOT_WORKSPACE_PATH}>
${this.#renderHeader()}
<div id="main">
<div id="left-column">${this.#renderLeftColumn()}</div>
<div id="right-column">${this.#renderRightColumn()}</div>
</div>
</umb-workspace-editor>
</umb-entity-detail-workspace-editor>
`;
}
#renderHeader() {
return html`
<umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>
<umb-workspace-entity-action-menu slot="action-menu"></umb-workspace-entity-action-menu>
`;
return html` <umb-workspace-header-name-editable slot="header"></umb-workspace-header-name-editable>`;
}
#renderLeftColumn() {

View File

@@ -82,12 +82,9 @@ export class UmbUserWorkspaceContext
There might be a less manual way to do this.
*/
onUserStoreChanges(user: EntityType | undefined) {
if (!user) {
//TODO: This solution is alright for now. But reconsider when we introduce signal-r
history.pushState(null, '', 'section/user-management');
return;
if (user) {
this._data.updateCurrent({ state: user.state, avatarUrls: user.avatarUrls });
}
this._data.updateCurrent({ state: user.state, avatarUrls: user.avatarUrls });
}
getState(): UmbUserStateEnum | null | undefined {

View File

@@ -4,7 +4,10 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
@customElement('umb-webhook-workspace-editor')
export class UmbWebhookWorkspaceEditorElement extends UmbLitElement {
override render() {
return html` <umb-workspace-editor back-path="section/settings/workspace/webhook-root"></umb-workspace-editor> `;
return html`
<umb-entity-detail-workspace-editor
back-path="section/settings/workspace/webhook-root"></umb-entity-detail-workspace-editor>
`;
}
static override styles = [UmbTextStyles];