Skip to content

Commit 86bbdfe

Browse files
madsrasmussennielslyngsoeCopilot
authored
<umb-content-workspace-property> DX (#19399)
* introduce umb-content-workspace-property to improve dx * make property responsible for observing the view guard * Update src/Umbraco.Web.UI.Client/src/packages/content/content/global-components/content-workspace-property.element.ts Co-authored-by: Copilot <[email protected]> * context consumer update tests * no need to import when exporting * only observe aliases * merge the two component for less complexity * added property settings * ensure this works with extension begin removed --------- Co-authored-by: Niels Lyngsø <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Niels Lyngsø <[email protected]>
1 parent 8d49078 commit 86bbdfe

File tree

7 files changed

+151
-147
lines changed

7 files changed

+151
-147
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class UmbContentTypePropertyStructureHelper<T extends UmbContentTypeModel
2626
// State which holds all the properties of the current container, this is a composition of all properties from the containers that matches our target [NL]
2727
#propertyStructure = new UmbArrayState<UmbPropertyTypeModel>([], (x) => x.unique);
2828
readonly propertyStructure = this.#propertyStructure.asObservable();
29+
readonly propertyAliases = this.#propertyStructure.asObservablePart((x) => x.map((e) => e.alias));
2930

3031
constructor(host: UmbControllerHost) {
3132
super(host);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '../constants.js';
2+
import { html, customElement, property, state, nothing } from '@umbraco-cms/backoffice/external/lit';
3+
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
4+
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
5+
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
6+
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
7+
import { UmbDataPathPropertyValueQuery } from '@umbraco-cms/backoffice/validation';
8+
9+
@customElement('umb-content-workspace-property')
10+
export class UmbContentWorkspacePropertyElement extends UmbLitElement {
11+
private _alias?: string | undefined;
12+
13+
@property({ type: String, attribute: 'alias' })
14+
public get alias(): string | undefined {
15+
return this._alias;
16+
}
17+
public set alias(value: string | undefined) {
18+
this._alias = value;
19+
this.#observePropertyType();
20+
}
21+
22+
@state()
23+
_datasetVariantId?: UmbVariantId;
24+
25+
@state()
26+
_dataPath?: string;
27+
28+
@state()
29+
_viewable?: boolean;
30+
31+
@state()
32+
_writeable?: boolean;
33+
34+
@state()
35+
_workspaceContext?: typeof UMB_CONTENT_WORKSPACE_CONTEXT.TYPE;
36+
37+
@state()
38+
_propertyType?: UmbPropertyTypeModel;
39+
40+
constructor() {
41+
super();
42+
43+
// The Property Dataset is local to the active variant, we use this to retrieve the variant we like to gather the value from.
44+
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (datasetContext) => {
45+
this._datasetVariantId = datasetContext?.getVariantId();
46+
});
47+
48+
// The Content Workspace Context is used to retrieve the property type we like to observe.
49+
// This gives us the configuration from the property type as part of the data type.
50+
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, async (workspaceContext) => {
51+
this._workspaceContext = workspaceContext;
52+
this.#observePropertyType();
53+
});
54+
}
55+
56+
async #observePropertyType() {
57+
if (!this._alias || !this._workspaceContext) return;
58+
59+
this.observe(await this._workspaceContext?.structure.propertyStructureByAlias(this._alias), (propertyType) => {
60+
this._propertyType = propertyType;
61+
this.#checkViewGuard();
62+
});
63+
}
64+
65+
#checkViewGuard() {
66+
if (!this._workspaceContext || !this._propertyType || !this._datasetVariantId) return;
67+
68+
const propertyVariantId = new UmbVariantId(
69+
this._propertyType.variesByCulture ? this._datasetVariantId.culture : null,
70+
this._propertyType.variesBySegment ? this._datasetVariantId.segment : null,
71+
);
72+
73+
this.observe(
74+
this._workspaceContext.propertyViewGuard.isPermittedForVariantAndProperty(
75+
propertyVariantId,
76+
this._propertyType,
77+
this._datasetVariantId,
78+
),
79+
(permitted) => {
80+
this._viewable = permitted;
81+
},
82+
`umbObservePropertyViewGuard`,
83+
);
84+
}
85+
86+
override willUpdate(changedProperties: Map<string, any>) {
87+
super.willUpdate(changedProperties);
88+
if (
89+
changedProperties.has('_propertyType') ||
90+
changedProperties.has('_datasetVariantId') ||
91+
changedProperties.has('_workspaceContext')
92+
) {
93+
if (this._datasetVariantId && this._propertyType && this._workspaceContext) {
94+
const propertyVariantId = new UmbVariantId(
95+
this._propertyType.variesByCulture ? this._datasetVariantId.culture : null,
96+
this._propertyType.variesBySegment ? this._datasetVariantId.segment : null,
97+
);
98+
this._dataPath = `$.values[${UmbDataPathPropertyValueQuery({
99+
alias: this._propertyType.alias,
100+
culture: propertyVariantId.culture,
101+
segment: propertyVariantId.segment,
102+
})}].value`;
103+
104+
this.observe(
105+
this._workspaceContext.propertyWriteGuard.isPermittedForVariantAndProperty(
106+
propertyVariantId,
107+
this._propertyType,
108+
propertyVariantId,
109+
),
110+
(write) => {
111+
this._writeable = write;
112+
},
113+
'observeView',
114+
);
115+
}
116+
}
117+
}
118+
119+
override render() {
120+
if (!this._viewable) return nothing;
121+
if (!this._dataPath || this._writeable === undefined) return nothing;
122+
123+
return html`<umb-property-type-based-property
124+
data-path=${this._dataPath}
125+
.property=${this._propertyType}
126+
?readonly=${!this._writeable}></umb-property-type-based-property>`;
127+
}
128+
}
129+
130+
export default UmbContentWorkspacePropertyElement;
131+
132+
declare global {
133+
interface HTMLElementTagNameMap {
134+
'umb-content-workspace-property': UmbContentWorkspacePropertyElement;
135+
}
136+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './content-workspace-property.element.js';

src/Umbraco.Web.UI.Client/src/packages/content/content/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ export * from './collection/index.js';
22
export * from './components/index.js';
33
export * from './constants.js';
44
export * from './controller/merge-content-variant-data.controller.js';
5+
export * from './global-components/index.js';
56
export * from './manager/index.js';
67
export * from './property-dataset-context/index.js';
78
export * from './workspace/index.js';
9+
810
export type * from './repository/index.js';
911
export type * from './types.js';
1012
export type * from './variant-picker/index.js';

src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-properties.element.ts

Lines changed: 10 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { UMB_CONTENT_WORKSPACE_CONTEXT } from '../../content-workspace.context-token.js';
2-
import { css, html, customElement, property, state, repeat, nothing } from '@umbraco-cms/backoffice/external/lit';
2+
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
33
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
44
import type {
55
UmbContentTypeModel,
@@ -8,17 +8,10 @@ import type {
88
} from '@umbraco-cms/backoffice/content-type';
99
import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type';
1010
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
11-
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
12-
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
13-
14-
import './content-editor-property.element.js';
1511

1612
@customElement('umb-content-workspace-view-edit-properties')
1713
export class UmbContentWorkspaceViewEditPropertiesElement extends UmbLitElement {
18-
#workspaceContext?: typeof UMB_CONTENT_WORKSPACE_CONTEXT.TYPE;
1914
#propertyStructureHelper = new UmbContentTypePropertyStructureHelper<UmbContentTypeModel>(this);
20-
#properties?: Array<UmbPropertyTypeModel>;
21-
#visiblePropertiesUniques: Array<string> = [];
2215

2316
@property({ type: String, attribute: 'container-id', reflect: false })
2417
public get containerId(): string | null | undefined {
@@ -29,86 +22,36 @@ export class UmbContentWorkspaceViewEditPropertiesElement extends UmbLitElement
2922
}
3023

3124
@state()
32-
_datasetVariantId?: UmbVariantId;
25+
_properties: Array<string> = [];
3326

3427
@state()
3528
_visibleProperties?: Array<UmbPropertyTypeModel>;
3629

3730
constructor() {
3831
super();
39-
40-
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (datasetContext) => {
41-
this._datasetVariantId = datasetContext?.getVariantId();
42-
this.#processPropertyStructure();
43-
});
44-
4532
this.consumeContext(UMB_CONTENT_WORKSPACE_CONTEXT, (workspaceContext) => {
46-
this.#workspaceContext = workspaceContext;
4733
this.#propertyStructureHelper.setStructureManager(
4834
// Assuming its the same content model type that we are working with here... [NL]
4935
workspaceContext?.structure as unknown as UmbContentTypeStructureManager<UmbContentTypeModel>,
5036
);
5137

5238
this.observe(
53-
this.#propertyStructureHelper.propertyStructure,
39+
this.#propertyStructureHelper.propertyAliases,
5440
(properties) => {
55-
this.#properties = properties;
56-
this.#processPropertyStructure();
41+
this._properties = properties;
5742
},
5843
'observePropertyStructure',
5944
);
6045
});
6146
}
6247

63-
#processPropertyStructure() {
64-
if (!this.#workspaceContext || !this.#properties || !this.#propertyStructureHelper || !this._datasetVariantId) {
65-
return;
66-
}
67-
68-
const propertyViewGuard = this.#workspaceContext.propertyViewGuard;
69-
70-
this.#properties.forEach((property) => {
71-
const propertyVariantId = new UmbVariantId(
72-
property.variesByCulture ? this._datasetVariantId?.culture : null,
73-
property.variesBySegment ? this._datasetVariantId?.segment : null,
74-
);
75-
this.observe(
76-
propertyViewGuard.isPermittedForVariantAndProperty(propertyVariantId, property, this._datasetVariantId!),
77-
(permitted) => {
78-
if (permitted) {
79-
this.#visiblePropertiesUniques.push(property.unique);
80-
this.#calculateVisibleProperties();
81-
} else {
82-
const index = this.#visiblePropertiesUniques.indexOf(property.unique);
83-
if (index !== -1) {
84-
this.#visiblePropertiesUniques.splice(index, 1);
85-
this.#calculateVisibleProperties();
86-
}
87-
}
88-
},
89-
`propertyViewGuard-permittedForVariantAndProperty-${property.unique}`,
90-
);
91-
});
92-
}
93-
94-
#calculateVisibleProperties() {
95-
this._visibleProperties = this.#properties!.filter((property) =>
96-
this.#visiblePropertiesUniques.includes(property.unique),
97-
);
98-
}
99-
10048
override render() {
101-
return this._datasetVariantId && this._visibleProperties
102-
? repeat(
103-
this._visibleProperties,
104-
(property) => property.alias,
105-
(property) =>
106-
html`<umb-content-workspace-view-edit-property
107-
class="property"
108-
.variantId=${this._datasetVariantId}
109-
.property=${property}></umb-content-workspace-view-edit-property>`,
110-
)
111-
: nothing;
49+
return repeat(
50+
this._properties,
51+
(property) => property,
52+
(property) =>
53+
html`<umb-content-workspace-property class="property" alias=${property}></umb-content-workspace-property>`,
54+
);
11255
}
11356

11457
static override styles = [

src/Umbraco.Web.UI.Client/src/packages/content/content/workspace/views/edit/content-editor-property.element.ts

Lines changed: 0 additions & 79 deletions
This file was deleted.

src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item/tree-item.element.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class UmbTreeItemElement extends UmbExtensionElementAndApiSlotElementBase
3131
// This method gets all extensions based on a type, then filters them based on the entity type. and then we get the alias of the first one [NL]
3232
createObservablePart(
3333
umbExtensionsRegistry.byTypeAndFilter(this.getExtensionType(), filterByEntityType),
34-
(x) => x[0].alias,
34+
(x) => x[0]?.alias,
3535
),
3636
(alias) => {
3737
this.alias = alias;

0 commit comments

Comments
 (0)