Hi All,
Managed to solve this one. If anyone needs something similar here is my code:
import { html, customElement, LitElement, property, css, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { UmbMediaDetailRepository } from '@umbraco-cms/backoffice/media';
import type { UmbBlockDataType } from '@umbraco-cms/backoffice/block';
import type { UmbBlockEditorCustomViewElement } from '@umbraco-cms/backoffice/block-custom-view';
import type { UmbMediaPickerPropertyValue } from '@umbraco-cms/backoffice/media';
@customElement('document-block-view')
export class DocumentBlockViewElement extends UmbElementMixin(LitElement) implements UmbBlockEditorCustomViewElement {
@property({ attribute: false })
content?: UmbBlockDataType;
@state()
document: UmbMediaPickerPropertyValue[] = [];
@state()
private _documentDetails: Map<string, { name: string, url: string, extension: string, size: number }> = new Map();
#mediaRepository = new UmbMediaDetailRepository(this);
override async updated(changedProperties: Map<string | number | symbol, unknown>) {
super.updated(changedProperties);
if (changedProperties.has('content') && this.content?.document) {
this.document = this.content.document as UmbMediaPickerPropertyValue[];
await this.fetchDocumentDetails();
}
}
async fetchDocumentDetails() {
if (!this.document) return;
for (const doc of this.document) {
if (doc.mediaKey && !this._documentDetails.has(doc.mediaKey)) {
const mediaItem = await this.resolveMediaItem(doc.mediaKey);
if (mediaItem) {
// Find properties by their unique alias
const uploadField = mediaItem.values.find(v => v.alias === 'umbracoFile');
const extensionField = mediaItem.values.find(v => v.alias === 'umbracoExtension');
const sizeField = mediaItem.values.find(v => v.alias === 'umbracoBytes');
// Check that the properties exist before using them
if (uploadField && extensionField && sizeField) {
this._documentDetails.set(doc.mediaKey, {
name: mediaItem.variants[0].name,
url: (uploadField.value as { src: string }).src,
extension: extensionField.value as string,
size: sizeField.value as number
});
this.requestUpdate();
}
}
}
}
}
async resolveMediaItem(mediaKey: string) {
const { data } = await this.#mediaRepository.requestByUnique(mediaKey);
return data;
}
render() {
return html`
<ul class="document-list">
${this.document.map((doc) => {
const details = this._documentDetails.get(doc.mediaKey || '');
return html`
<li>
<a href="${details?.url}" target="_blank" rel="noopener noreferrer">
${details ? `${details.name} (${details.extension}, ${details.size} bytes)` : 'Loading...'}
</a>
</li>
`;
})}
</ul>`;
}
static styles = [
css`
:host {
display: block;
height: 100%;
box-sizing: border-box;
background-color: white;
border-radius: 9px;
padding: 12px;
}
.document-list {
list-style-type:- disclosure-closed;
padding-inline-start: 20px;
}
.document-list a {
text-decoration: none;
color: var(--uui-color-interactive, #2152a3);
}
.document-list a:hover {
text-decoration: underline;
}
`,
];
}
export default DocumentBlockViewElement;
declare global {
interface HTMLElementTagNameMap {
'document-block-view': DocumentBlockViewElement;
}
}