Skip to content

Commit 7572ea3

Browse files
Feature: Content Workspace Icon (#19292)
* add slot for icon * expose icon data * render icon * load type for scaffold * rename * render icon for media * add observable for content type icon * request data in data source * wire up document scaffolding * remove unused * export server data source * render icon for member * rename data source to align with other detail sources * rename data source * remove unused styling * remove console log Co-authored-by: Copilot <[email protected]> * remove console log Co-authored-by: Copilot <[email protected]> * remove console log * Update detail-repository-base.ts * Update document-workspace-split-view.element.ts --------- Co-authored-by: Copilot <[email protected]>
1 parent ec6a38e commit 7572ea3

File tree

21 files changed

+190
-140
lines changed

21 files changed

+190
-140
lines changed

src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-data-source.interface.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { UmbDataSourceResponse } from '../data-source-response.interface.js';
22
import type { UmbReadDetailDataSource } from './read/index.js';
3+
import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils';
34
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
45

56
export interface UmbDetailDataSourceConstructor<
@@ -10,7 +11,7 @@ export interface UmbDetailDataSourceConstructor<
1011
}
1112

1213
export interface UmbDetailDataSource<DetailType> extends UmbReadDetailDataSource<DetailType> {
13-
createScaffold(preset?: Partial<DetailType>): Promise<UmbDataSourceResponse<DetailType>>;
14+
createScaffold(preset?: UmbDeepPartialObject<DetailType>): Promise<UmbDataSourceResponse<DetailType>>;
1415
create(data: DetailType, parentUnique: string | null): Promise<UmbDataSourceResponse<DetailType>>;
1516
update(data: DetailType): Promise<UmbDataSourceResponse<DetailType>>;
1617
delete(unique: string): Promise<UmbDataSourceResponse<unknown>>;

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
77
import type { UmbDetailStore } from '@umbraco-cms/backoffice/store';
88
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
99
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
10+
import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils';
1011

1112
export abstract class UmbDetailRepositoryBase<
1213
DetailModelType extends UmbEntityModel,
@@ -44,11 +45,13 @@ export abstract class UmbDetailRepositoryBase<
4445

4546
/**
4647
* Creates a scaffold
47-
* @param {Partial<DetailModelType>} [preset]
48+
* @param {UmbDeepPartialObject<DetailModelType>} [preset]
4849
* @returns {*}
4950
* @memberof UmbDetailRepositoryBase
5051
*/
51-
async createScaffold(preset?: Partial<DetailModelType>): Promise<UmbRepositoryResponse<DetailModelType>> {
52+
async createScaffold(
53+
preset?: UmbDeepPartialObject<DetailModelType>,
54+
): Promise<UmbRepositoryResponse<DetailModelType>> {
5255
return this.detailDataSource.createScaffold(preset);
5356
}
5457

src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view.element.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export class UmbWorkspaceSplitViewElement extends UmbLitElement {
6767
back-path=${ifDefined(this.backPath)}
6868
.hideNavigation=${!this.displayNavigation}
6969
.enforceNoFooter=${true}>
70+
<slot id="icon" name="icon" slot="header"></slot>
7071
<slot id="header" name="variant-selector" slot="header" @slotchange=${this.#onVariantSelectorSlotChanged}>
7172
${when(
7273
!this._variantSelectorSlotHasContent,
@@ -106,6 +107,12 @@ export class UmbWorkspaceSplitViewElement extends UmbLitElement {
106107
flex: 1 1 auto;
107108
display: block;
108109
}
110+
111+
#icon {
112+
display: inline-block;
113+
font-size: var(--uui-size-6);
114+
margin-right: var(--uui-size-space-4);
115+
}
109116
`,
110117
];
111118
}

src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
2+
import type { UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils';
23

34
export interface UmbEntityDetailWorkspaceContextArgs {
45
entityType: string;
@@ -13,5 +14,5 @@ export type UmbEntityWorkspaceContextArgs = UmbEntityDetailWorkspaceContextArgs;
1314

1415
export interface UmbEntityDetailWorkspaceContextCreateArgs<DetailModelType> {
1516
parent: UmbEntityModel;
16-
preset?: Partial<DetailModelType>;
17+
preset?: UmbDeepPartialObject<DetailModelType>;
1718
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { UmbDocumentTypeDetailRepository } from './document-type-detail.repository.js';
2+
export * from './document-type-detail.server.data-source.js';

src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/detail/document-detail.server.data-source.ts

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,59 @@ import type {
77
UpdateDocumentRequestModel,
88
} from '@umbraco-cms/backoffice/external/backend-api';
99
import { DocumentService } from '@umbraco-cms/backoffice/external/backend-api';
10-
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
1110
import { tryExecute } from '@umbraco-cms/backoffice/resources';
11+
import { umbDeepMerge, type UmbDeepPartialObject } from '@umbraco-cms/backoffice/utils';
12+
import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models';
13+
import { UmbDocumentTypeDetailServerDataSource } from '@umbraco-cms/backoffice/document-type';
14+
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
1215

1316
/**
1417
* A data source for the Document that fetches data from the server
1518
* @class UmbDocumentServerDataSource
1619
* @implements {RepositoryDetailDataSource}
1720
*/
18-
export class UmbDocumentServerDataSource implements UmbDetailDataSource<UmbDocumentDetailModel> {
19-
#host: UmbControllerHost;
20-
21-
/**
22-
* Creates an instance of UmbDocumentServerDataSource.
23-
* @param {UmbControllerHost} host - The controller host for this controller to be appended to
24-
* @memberof UmbDocumentServerDataSource
25-
*/
26-
constructor(host: UmbControllerHost) {
27-
this.#host = host;
28-
}
29-
21+
export class UmbDocumentServerDataSource
22+
extends UmbControllerBase
23+
implements UmbDetailDataSource<UmbDocumentDetailModel>
24+
{
3025
/**
3126
* Creates a new Document scaffold
3227
* @param preset
3328
* @returns { UmbDocumentDetailModel }
3429
* @memberof UmbDocumentServerDataSource
3530
*/
36-
async createScaffold(preset: Partial<UmbDocumentDetailModel> = {}) {
37-
const data: UmbDocumentDetailModel = {
31+
async createScaffold(preset: UmbDeepPartialObject<UmbDocumentDetailModel> = {}) {
32+
let documentTypeIcon: string | null = null;
33+
let documentTypeCollection: UmbReferenceByUnique | null = null;
34+
35+
const documentTypeUnique = preset.documentType?.unique;
36+
37+
if (!documentTypeUnique) {
38+
throw new Error('Document type unique is missing');
39+
}
40+
41+
const { data } = await new UmbDocumentTypeDetailServerDataSource(this).read(documentTypeUnique);
42+
documentTypeIcon = data?.icon ?? null;
43+
documentTypeCollection = data?.collection ?? null;
44+
45+
const defaultData: UmbDocumentDetailModel = {
3846
entityType: UMB_DOCUMENT_ENTITY_TYPE,
3947
unique: UmbId.new(),
4048
template: null,
4149
documentType: {
42-
unique: '',
43-
collection: null,
44-
icon: null,
50+
unique: documentTypeUnique,
51+
collection: documentTypeCollection,
52+
icon: documentTypeIcon,
4553
},
4654
isTrashed: false,
4755
values: [],
4856
variants: [],
49-
...preset,
5057
};
5158

52-
return { data };
53-
}
59+
const scaffold = umbDeepMerge(defaultData, preset) as UmbDocumentDetailModel;
5460

55-
/**
56-
* Creates a new variant scaffold.
57-
* @returns A new variant scaffold.
58-
*/
59-
/*
60-
// TDOD: remove if not used
61-
createVariantScaffold(): UmbDocumentVariantModel {
62-
return {
63-
state: null,
64-
culture: null,
65-
segment: null,
66-
name: '',
67-
publishDate: null,
68-
createDate: null,
69-
updateDate: null,
70-
};
61+
return { data: scaffold };
7162
}
72-
*/
7363

7464
/**
7565
* Fetches a Document with the given id from the server
@@ -80,7 +70,7 @@ export class UmbDocumentServerDataSource implements UmbDetailDataSource<UmbDocum
8070
async read(unique: string) {
8171
if (!unique) throw new Error('Unique is missing');
8272

83-
const { data, error } = await tryExecute(this.#host, DocumentService.getDocumentById({ path: { id: unique } }));
73+
const { data, error } = await tryExecute(this, DocumentService.getDocumentById({ path: { id: unique } }));
8474

8575
if (error || !data) {
8676
return { error };
@@ -147,7 +137,7 @@ export class UmbDocumentServerDataSource implements UmbDetailDataSource<UmbDocum
147137
};
148138

149139
const { data, error } = await tryExecute(
150-
this.#host,
140+
this,
151141
DocumentService.postDocument({
152142
body: body,
153143
}),
@@ -177,7 +167,7 @@ export class UmbDocumentServerDataSource implements UmbDetailDataSource<UmbDocum
177167
};
178168

179169
const { error } = await tryExecute(
180-
this.#host,
170+
this,
181171
DocumentService.putDocumentById({
182172
path: { id: model.unique },
183173
body: body,
@@ -199,6 +189,6 @@ export class UmbDocumentServerDataSource implements UmbDetailDataSource<UmbDocum
199189
*/
200190
async delete(unique: string) {
201191
if (!unique) throw new Error('Unique is missing');
202-
return tryExecute(this.#host, DocumentService.deleteDocumentById({ path: { id: unique } }));
192+
return tryExecute(this, DocumentService.deleteDocumentById({ path: { id: unique } }));
203193
}
204194
}

src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-split-view.element.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from './document-workspace.context-token.js';
22
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3-
import { css, html, nothing, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
3+
import { css, html, nothing, customElement, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit';
44
import type { ActiveVariant } from '@umbraco-cms/backoffice/workspace';
55
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
66

@@ -14,27 +14,36 @@ export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement {
1414
@state()
1515
_variants?: Array<ActiveVariant>;
1616

17+
@state()
18+
_icon?: string;
19+
1720
constructor() {
1821
super();
1922

2023
// TODO: Refactor: use a split view workspace context token: [NL]
2124
this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => {
2225
this._workspaceContext = context;
23-
this._observeActiveVariantInfo();
26+
this.#observeActiveVariantInfo();
27+
this.#observeIcon();
2428
});
2529
}
2630

27-
private _observeActiveVariantInfo() {
28-
if (!this._workspaceContext) return;
31+
#observeActiveVariantInfo() {
2932
this.observe(
30-
this._workspaceContext.splitView.activeVariantsInfo,
33+
this._workspaceContext?.splitView.activeVariantsInfo,
3134
(variants) => {
3235
this._variants = variants;
3336
},
3437
'_observeActiveVariantsInfo',
3538
);
3639
}
3740

41+
#observeIcon() {
42+
this.observe(this._workspaceContext?.contentTypeIcon, (icon) => {
43+
this._icon = icon ?? undefined;
44+
});
45+
}
46+
3847
override render() {
3948
return this._variants
4049
? html`<div id="splitViews">
@@ -46,6 +55,7 @@ export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement {
4655
<umb-workspace-split-view
4756
.splitViewIndex=${view.index}
4857
.displayNavigation=${view.index === this._variants!.length - 1}>
58+
<umb-icon slot="icon" name=${ifDefined(this._icon)}></umb-icon>
4959
<umb-document-workspace-split-view-variant-selector
5060
slot="variant-selector"></umb-document-workspace-split-view-variant-selector>
5161
</umb-workspace-split-view>

src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export class UmbDocumentWorkspaceContext
6767
readonly contentTypeHasCollection = this._data.createObservablePartOfCurrent(
6868
(data) => !!data?.documentType.collection,
6969
);
70+
readonly contentTypeIcon = this._data.createObservablePartOfCurrent((data) => data?.documentType.icon || null);
71+
7072
readonly templateId = this._data.createObservablePartOfCurrent((data) => data?.template?.unique || null);
7173

7274
#isTrashedContext = new UmbIsTrashedEntityContext(this);
@@ -303,7 +305,6 @@ export class UmbDocumentWorkspaceContext
303305
preset: {
304306
documentType: {
305307
unique: documentTypeUnique,
306-
collection: null,
307308
},
308309
},
309310
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { UmbMediaTypeDetailRepository } from './media-type-detail.repository.js';
2+
export * from './media-type-detail.server.data-source.js';

src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/detail/media-type-detail.repository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { UmbMediaTypeDetailModel } from '../../types.js';
2-
import { UmbMediaTypeServerDataSource } from './media-type-detail.server.data-source.js';
2+
import { UmbMediaTypeDetailServerDataSource } from './media-type-detail.server.data-source.js';
33
import { UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT } from './media-type-detail.store.context-token.js';
44
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
55
import { UmbDetailRepositoryBase } from '@umbraco-cms/backoffice/repository';
66
export class UmbMediaTypeDetailRepository extends UmbDetailRepositoryBase<UmbMediaTypeDetailModel> {
77
constructor(host: UmbControllerHost) {
8-
super(host, UmbMediaTypeServerDataSource, UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT);
8+
super(host, UmbMediaTypeDetailServerDataSource, UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT);
99
}
1010
}
1111

0 commit comments

Comments
 (0)