Document URLs Data Resolver (#19316)
* remove padding * add document urls data resolver * use in url info app * handle invariant cases * do not render culture if all links have the same culture * use if defined * handle variant with no links * Update types.ts * fix lint errors * get variant aware document data * remove unused * use media item repository * temp remove check * populate url * add spacing to reference app * reset the url when removing document or media * add validator * make url input required --------- Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
This commit is contained in:
@@ -22,10 +22,6 @@ export class UmbWorkspaceInfoAppLayoutElement extends UmbLitElement {
|
||||
uui-box {
|
||||
--uui-box-default-padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
padding-left: var(--uui-size-space-4);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import type { UmbDocumentUrlModel } from './repository/types.js';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
|
||||
/**
|
||||
* A controller for resolving data for document urls
|
||||
* @exports
|
||||
* @class UmbDocumentUrlsDataResolver
|
||||
* @augments {UmbControllerBase}
|
||||
*/
|
||||
export class UmbDocumentUrlsDataResolver extends UmbControllerBase {
|
||||
#appCulture?: string;
|
||||
#propertyDataSetCulture?: UmbVariantId;
|
||||
#data?: Array<UmbDocumentUrlModel> | undefined;
|
||||
|
||||
#init: Promise<unknown>;
|
||||
|
||||
#urls = new UmbArrayState<UmbDocumentUrlModel>([], (url) => url.url);
|
||||
/**
|
||||
* The urls for the current culture
|
||||
* @returns {ObservableArray<UmbDocumentUrlModel>} The urls for the current culture
|
||||
* @memberof UmbDocumentUrlsDataResolver
|
||||
*/
|
||||
public readonly urls = this.#urls.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
|
||||
// TODO: listen for UMB_VARIANT_CONTEXT when available
|
||||
this.#init = Promise.all([
|
||||
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => {
|
||||
this.#propertyDataSetCulture = context?.getVariantId();
|
||||
this.#setCultureAwareValues();
|
||||
}).asPromise(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current data
|
||||
* @returns {Array<UmbDocumentUrlModel> | undefined} The current data
|
||||
* @memberof UmbDocumentUrlsDataResolver
|
||||
*/
|
||||
getData(): Array<UmbDocumentUrlModel> | undefined {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current data
|
||||
* @param {Array<UmbDocumentUrlModel> | undefined} data The current data
|
||||
* @memberof UmbDocumentUrlsDataResolver
|
||||
*/
|
||||
setData(data: Array<UmbDocumentUrlModel> | undefined) {
|
||||
this.#data = data;
|
||||
|
||||
if (!this.#data) {
|
||||
this.#urls.setValue([]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.#setCultureAwareValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the urls for the current culture
|
||||
* @returns {(Promise<Array<UmbDocumentUrlModel> | []>)} The urls for the current culture
|
||||
* @memberof UmbDocumentUrlsDataResolver
|
||||
*/
|
||||
async getUrls(): Promise<Array<UmbDocumentUrlModel> | []> {
|
||||
await this.#init;
|
||||
return this.#urls.getValue();
|
||||
}
|
||||
|
||||
#setCultureAwareValues() {
|
||||
this.#setUrls();
|
||||
}
|
||||
|
||||
#setUrls() {
|
||||
const data = this.#getDataForCurrentCulture();
|
||||
this.#urls.setValue(data ?? []);
|
||||
}
|
||||
|
||||
#getCurrentCulture(): string | undefined {
|
||||
return this.#propertyDataSetCulture?.culture || this.#appCulture;
|
||||
}
|
||||
|
||||
#getDataForCurrentCulture(): Array<UmbDocumentUrlModel> | undefined {
|
||||
const culture = this.#getCurrentCulture();
|
||||
// If there is no culture context (invariant data) we return all urls
|
||||
return culture ? this.#data?.filter((x) => x.culture === culture) : this.#data;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export { UmbDocumentUrlRepository, UMB_DOCUMENT_URL_REPOSITORY_ALIAS } from './repository/index.js';
|
||||
|
||||
export * from './constants.js';
|
||||
export * from './document-urls-data-resolver.js';
|
||||
|
||||
@@ -2,7 +2,17 @@ import { UmbDocumentUrlRepository } from '../repository/index.js';
|
||||
import type { UmbDocumentVariantOptionModel } from '../../types.js';
|
||||
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../workspace/constants.js';
|
||||
import type { UmbDocumentUrlModel } from '../repository/types.js';
|
||||
import { css, customElement, html, nothing, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbDocumentUrlsDataResolver } from '../document-urls-data-resolver.js';
|
||||
import {
|
||||
css,
|
||||
customElement,
|
||||
html,
|
||||
ifDefined,
|
||||
nothing,
|
||||
repeat,
|
||||
state,
|
||||
when,
|
||||
} from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbEntityActionEvent } from '@umbraco-cms/backoffice/entity-action';
|
||||
import { UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action';
|
||||
@@ -10,11 +20,12 @@ import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
|
||||
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
|
||||
import { debounce } from '@umbraco-cms/backoffice/utils';
|
||||
import { UMB_APP_LANGUAGE_CONTEXT } from '@umbraco-cms/backoffice/language';
|
||||
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
|
||||
interface UmbDocumentInfoViewLink {
|
||||
culture: string;
|
||||
url: string | undefined;
|
||||
culture: string | null;
|
||||
url: string | null | undefined;
|
||||
state: DocumentVariantStateModel | null | undefined;
|
||||
}
|
||||
|
||||
@@ -37,13 +48,13 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
@state()
|
||||
private _links: Array<UmbDocumentInfoViewLink> = [];
|
||||
|
||||
@state()
|
||||
private _defaultCulture?: string;
|
||||
|
||||
#urls: Array<UmbDocumentUrlModel> = [];
|
||||
|
||||
#documentWorkspaceContext?: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE;
|
||||
#eventContext?: typeof UMB_ACTION_EVENT_CONTEXT.TYPE;
|
||||
#propertyDataSetVariantId?: UmbVariantId;
|
||||
|
||||
#documentUrlsDataResolver? = new UmbDocumentUrlsDataResolver(this);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -88,20 +99,26 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
});
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (instance) => {
|
||||
this.observe(instance?.appDefaultLanguage, (value) => {
|
||||
this._defaultCulture = value?.unique;
|
||||
this.#setLinks();
|
||||
});
|
||||
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => {
|
||||
this.#propertyDataSetVariantId = context?.getVariantId();
|
||||
this.#setLinks();
|
||||
});
|
||||
|
||||
this.observe(this.#documentUrlsDataResolver?.urls, (urls) => {
|
||||
this.#urls = urls ?? [];
|
||||
this.#setLinks();
|
||||
});
|
||||
}
|
||||
|
||||
#setLinks() {
|
||||
const links: Array<UmbDocumentInfoViewLink> = this.#urls.map((u) => {
|
||||
const culture = u.culture ?? this._defaultCulture ?? '';
|
||||
const url = u.url;
|
||||
const links: Array<UmbDocumentInfoViewLink> = this.#urls.map((url) => {
|
||||
const culture = url.culture;
|
||||
const state = this._variantOptions?.find((variantOption) => variantOption.culture === culture)?.variant?.state;
|
||||
return { culture, url, state };
|
||||
return {
|
||||
culture,
|
||||
url: url.url,
|
||||
state,
|
||||
};
|
||||
});
|
||||
|
||||
this._links = links;
|
||||
@@ -124,14 +141,12 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
if (!this._unique) return;
|
||||
|
||||
this._loading = true;
|
||||
this.#urls = [];
|
||||
this.#documentUrlsDataResolver?.setData([]);
|
||||
|
||||
const { data } = await this.#documentUrlRepository.requestItems([this._unique]);
|
||||
|
||||
if (data?.length) {
|
||||
const item = data[0];
|
||||
this.#urls = item.urls;
|
||||
this.#setLinks();
|
||||
this.#documentUrlsDataResolver?.setData(data[0].urls);
|
||||
}
|
||||
|
||||
this._loading = false;
|
||||
@@ -207,7 +222,7 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<a class="link-item" href=${this.#getTargetUrl(link.url)} target="_blank">
|
||||
<a class="link-item" href=${ifDefined(this.#getTargetUrl(link.url))} target="_blank">
|
||||
<span>
|
||||
${this.#renderLinkCulture(link.culture)}
|
||||
<span>${link.url}</span>
|
||||
@@ -218,9 +233,9 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
#renderNoLinks() {
|
||||
return html` ${this._variantOptions?.map((variantOption) =>
|
||||
this.#renderEmptyLink(variantOption.culture, variantOption.variant?.state),
|
||||
)}`;
|
||||
return html` ${this._variantOptions
|
||||
?.filter((variantOption) => variantOption.culture === this.#propertyDataSetVariantId?.culture)
|
||||
.map((variantOption) => this.#renderEmptyLink(variantOption.culture, variantOption.variant?.state))}`;
|
||||
}
|
||||
|
||||
#renderEmptyLink(culture: string | null, state: DocumentVariantStateModel | null | undefined) {
|
||||
@@ -235,6 +250,8 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
#renderLinkCulture(culture: string | null) {
|
||||
if (!culture) return nothing;
|
||||
if (this._links.length === 1) return nothing;
|
||||
const allLinksHaveSameCulture = this._links?.every((link) => link.culture === culture);
|
||||
if (allLinksHaveSameCulture) return nothing;
|
||||
return html`<span class="culture">${culture}</span>`;
|
||||
}
|
||||
|
||||
@@ -249,10 +266,6 @@ export class UmbDocumentLinksWorkspaceInfoAppElement extends UmbLitElement {
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
uui-box {
|
||||
--uui-box-default-padding: 0;
|
||||
}
|
||||
|
||||
#loader-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -4,6 +4,6 @@ export interface UmbDocumentUrlsModel {
|
||||
}
|
||||
|
||||
export interface UmbDocumentUrlModel {
|
||||
culture?: string | null;
|
||||
culture: string | null;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbDocumentUrlRepository, UmbDocumentUrlsDataResolver } from '@umbraco-cms/backoffice/document';
|
||||
import { UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media';
|
||||
|
||||
/**
|
||||
* @element umb-input-multi-url
|
||||
@@ -129,6 +131,7 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement,
|
||||
this.#urls = [...data]; // Unfreeze data coming from State, so we can manipulate it.
|
||||
super.value = this.#urls.map((x) => x.url).join(',');
|
||||
this.#sorter.setModel(this.#urls);
|
||||
this.#populateLinksUrl();
|
||||
}
|
||||
get urls(): Array<UmbLinkPickerLink> {
|
||||
return this.#urls;
|
||||
@@ -160,6 +163,9 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement,
|
||||
@state()
|
||||
private _modalRoute?: UmbModalRouteBuilder;
|
||||
|
||||
@state()
|
||||
_resolvedLinkUrls: Array<{ unique: string; url: string }> = [];
|
||||
|
||||
#linkPickerModal;
|
||||
|
||||
constructor() {
|
||||
@@ -229,6 +235,49 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement,
|
||||
});
|
||||
}
|
||||
|
||||
#populateLinksUrl() {
|
||||
// Documents and media have URLs saved in the local link format. Display the actual URL to align with what
|
||||
// the user sees when they selected it initially.
|
||||
this.#urls.forEach(async (link) => {
|
||||
if (!link.unique) return;
|
||||
|
||||
let url: string | undefined = undefined;
|
||||
switch (link.type) {
|
||||
case 'document': {
|
||||
url = await this.#getUrlForDocument(link.unique);
|
||||
break;
|
||||
}
|
||||
case 'media': {
|
||||
url = await this.#getUrlForMedia(link.unique);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
const resolvedUrl = { unique: link.unique, url };
|
||||
this._resolvedLinkUrls = [...this._resolvedLinkUrls, resolvedUrl];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async #getUrlForDocument(unique: string) {
|
||||
const documentUrlRepository = new UmbDocumentUrlRepository(this);
|
||||
const { data: documentUrlData } = await documentUrlRepository.requestItems([unique]);
|
||||
const urlsItem = documentUrlData?.[0];
|
||||
const dataResolver = new UmbDocumentUrlsDataResolver(this);
|
||||
dataResolver.setData(urlsItem?.urls);
|
||||
const resolvedUrls = await dataResolver.getUrls();
|
||||
return resolvedUrls?.[0]?.url ?? '';
|
||||
}
|
||||
|
||||
async #getUrlForMedia(unique: string) {
|
||||
const mediaUrlRepository = new UmbMediaUrlRepository(this);
|
||||
const { data: mediaUrlData } = await mediaUrlRepository.requestItems([unique]);
|
||||
return mediaUrlData?.[0].url ?? '';
|
||||
}
|
||||
|
||||
async #requestRemoveItem(index: number) {
|
||||
const item = this.#urls[index];
|
||||
if (!item) throw new Error('Could not find item at index: ' + index);
|
||||
@@ -307,12 +356,13 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement,
|
||||
#renderItem(link: UmbLinkPickerLink, index: number) {
|
||||
const unique = this.#getUnique(link);
|
||||
const href = this.readonly ? undefined : (this._modalRoute?.({ index }) ?? undefined);
|
||||
const resolvedUrl = this._resolvedLinkUrls.find((url) => url.unique === link.unique)?.url ?? '';
|
||||
return html`
|
||||
<uui-ref-node
|
||||
id=${unique}
|
||||
href=${ifDefined(href)}
|
||||
name=${link.name || ''}
|
||||
detail=${(link.url || '') + (link.queryString || '')}
|
||||
detail=${resolvedUrl + (link.queryString || '')}
|
||||
?readonly=${this.readonly}>
|
||||
<umb-icon slot="icon" name=${link.icon || 'icon-link'}></umb-icon>
|
||||
${when(
|
||||
|
||||
@@ -6,13 +6,83 @@ import type {
|
||||
} from './link-picker-modal.token.js';
|
||||
import { css, customElement, html, nothing, query, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { isUmbracoFolder, UmbMediaTypeStructureRepository } from '@umbraco-cms/backoffice/media-type';
|
||||
import { umbBindToValidation, UmbValidationContext } from '@umbraco-cms/backoffice/validation';
|
||||
import {
|
||||
UMB_VALIDATION_CONTEXT,
|
||||
umbBindToValidation,
|
||||
UmbObserveValidationStateController,
|
||||
UmbValidationContext,
|
||||
type UmbValidator,
|
||||
} from '@umbraco-cms/backoffice/validation';
|
||||
import { umbConfirmModal, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbDocumentDetailRepository, UmbDocumentUrlRepository } from '@umbraco-cms/backoffice/document';
|
||||
import { UmbMediaDetailRepository, UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media';
|
||||
import {
|
||||
UmbDocumentItemDataResolver,
|
||||
UmbDocumentItemRepository,
|
||||
UmbDocumentUrlRepository,
|
||||
UmbDocumentUrlsDataResolver,
|
||||
} from '@umbraco-cms/backoffice/document';
|
||||
import { UmbMediaItemRepository, UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media';
|
||||
import type { UmbInputDocumentElement } from '@umbraco-cms/backoffice/document';
|
||||
import type { UmbInputMediaElement } from '@umbraco-cms/backoffice/media';
|
||||
import type { UUIBooleanInputEvent, UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UUIBooleanInputEvent, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { umbFocus } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
class UmbLinkPickerValueValidator extends UmbControllerBase implements UmbValidator {
|
||||
#context?: typeof UMB_VALIDATION_CONTEXT.TYPE;
|
||||
|
||||
#isValid = true;
|
||||
get isValid(): boolean {
|
||||
return this.#isValid;
|
||||
}
|
||||
|
||||
#value: unknown;
|
||||
|
||||
#unique = 'UmbLinkPickerValueValidator';
|
||||
|
||||
setValue(value: unknown) {
|
||||
this.#value = value;
|
||||
this.validate();
|
||||
}
|
||||
|
||||
getValue(): unknown {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
// The path to the data that this validator is validating.
|
||||
readonly #dataPath: string;
|
||||
|
||||
constructor(host: UmbControllerHost, dataPath: string) {
|
||||
super(host);
|
||||
this.#dataPath = dataPath;
|
||||
this.consumeContext(UMB_VALIDATION_CONTEXT, (context) => {
|
||||
if (this.#context) {
|
||||
this.#context.removeValidator(this);
|
||||
}
|
||||
this.#context = context;
|
||||
context?.addValidator(this);
|
||||
});
|
||||
}
|
||||
|
||||
async validate(): Promise<void> {
|
||||
this.#isValid = !!this.getValue();
|
||||
|
||||
if (this.#isValid) {
|
||||
this.#context?.messages.removeMessageByKey(this.#unique);
|
||||
} else {
|
||||
this.#context?.messages.addMessage(
|
||||
'client',
|
||||
this.#dataPath,
|
||||
'#linkPicker_modalAnchorValidationMessage',
|
||||
this.#unique,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {}
|
||||
|
||||
focusFirstInvalidElement(): void {}
|
||||
}
|
||||
|
||||
type UmbInputPickerEvent = CustomEvent & { target: { value?: string } };
|
||||
|
||||
@@ -31,14 +101,22 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
hideTarget: false,
|
||||
};
|
||||
|
||||
@state()
|
||||
private _missingLinkUrl = false;
|
||||
|
||||
@query('umb-input-document')
|
||||
private _documentPickerElement?: UmbInputDocumentElement;
|
||||
|
||||
@query('umb-input-media')
|
||||
private _mediaPickerElement?: UmbInputMediaElement;
|
||||
|
||||
@query('#link-anchor', true)
|
||||
private _linkAnchorInput?: UUIInputElement;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
new UmbObserveValidationStateController(this, '$.type', (invalid) => {
|
||||
this._missingLinkUrl = invalid;
|
||||
});
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
@@ -57,14 +135,12 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
|
||||
this.#getMediaTypes();
|
||||
this.populateLinkUrl();
|
||||
}
|
||||
|
||||
protected override firstUpdated() {
|
||||
this._linkAnchorInput?.addValidator(
|
||||
'valueMissing',
|
||||
() => this.localize.term('linkPicker_modalAnchorValidationMessage'),
|
||||
() => !this.value.link.name && !this.value.link.queryString,
|
||||
);
|
||||
const validator = new UmbLinkPickerValueValidator(this, '$.type');
|
||||
|
||||
this.observe(this.modalContext?.value, (value) => {
|
||||
validator.setValue(value?.link.type);
|
||||
});
|
||||
}
|
||||
|
||||
async #getMediaTypes() {
|
||||
@@ -78,7 +154,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
async populateLinkUrl() {
|
||||
// Documents and media have URLs saved in the local link format. Display the actual URL to align with what
|
||||
// the user sees when they selected it initially.
|
||||
if (!this.value.link?.unique || this.value.link?.url?.indexOf('localLink') === -1) return;
|
||||
if (!this.value.link?.unique) return;
|
||||
|
||||
let url: string | undefined = undefined;
|
||||
switch (this.value.link.type) {
|
||||
@@ -156,21 +232,25 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
if (unique) {
|
||||
switch (type) {
|
||||
case 'document': {
|
||||
const documentRepository = new UmbDocumentDetailRepository(this);
|
||||
const { data: documentData } = await documentRepository.requestByUnique(unique);
|
||||
if (documentData) {
|
||||
icon = documentData.documentType.icon;
|
||||
name = documentData.variants[0].name;
|
||||
const documentRepository = new UmbDocumentItemRepository(this);
|
||||
const { data: documentItems } = await documentRepository.requestItems([unique]);
|
||||
const documentItem = documentItems?.[0];
|
||||
if (documentItem) {
|
||||
const itemDataResolver = new UmbDocumentItemDataResolver(this);
|
||||
itemDataResolver.setData(documentItem);
|
||||
icon = await itemDataResolver.getIcon();
|
||||
name = await itemDataResolver.getName();
|
||||
url = await this.#getUrlForDocument(unique);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'media': {
|
||||
const mediaRepository = new UmbMediaDetailRepository(this);
|
||||
const { data: mediaData } = await mediaRepository.requestByUnique(unique);
|
||||
if (mediaData) {
|
||||
icon = mediaData.mediaType.icon;
|
||||
name = mediaData.variants[0].name;
|
||||
const mediaRepository = new UmbMediaItemRepository(this);
|
||||
const { data: mediaData } = await mediaRepository.requestItems([unique]);
|
||||
const mediaItem = mediaData?.[0];
|
||||
if (mediaItem) {
|
||||
icon = mediaItem.mediaType.icon;
|
||||
name = mediaItem.variants[0].name;
|
||||
url = await this.#getUrlForMedia(unique);
|
||||
}
|
||||
break;
|
||||
@@ -178,6 +258,9 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// The selection was removed
|
||||
} else {
|
||||
this.#resetUrl();
|
||||
}
|
||||
|
||||
const link = {
|
||||
@@ -196,7 +279,11 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
async #getUrlForDocument(unique: string) {
|
||||
const documentUrlRepository = new UmbDocumentUrlRepository(this);
|
||||
const { data: documentUrlData } = await documentUrlRepository.requestItems([unique]);
|
||||
return documentUrlData && documentUrlData[0].urls.length > 0 ? (documentUrlData?.[0].urls[0].url ?? '') : '';
|
||||
const urlsItem = documentUrlData?.[0];
|
||||
const dataResolver = new UmbDocumentUrlsDataResolver(this);
|
||||
dataResolver.setData(urlsItem?.urls);
|
||||
const resolvedUrls = await dataResolver.getUrls();
|
||||
return resolvedUrls?.[0]?.url ?? '';
|
||||
}
|
||||
|
||||
async #getUrlForMedia(unique: string) {
|
||||
@@ -215,6 +302,10 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
});
|
||||
}
|
||||
|
||||
this.#resetUrl();
|
||||
}
|
||||
|
||||
#resetUrl() {
|
||||
this.#partialUpdateLink({ type: null, url: null });
|
||||
}
|
||||
|
||||
@@ -239,7 +330,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
return html`
|
||||
<umb-body-layout
|
||||
headline=${this.localize.term(
|
||||
this.modalContext?.data.isNew ? 'defaultdialogs_addLink' : 'defaultdialogs_updateLink',
|
||||
this.modalContext?.data?.isNew ? 'defaultdialogs_addLink' : 'defaultdialogs_updateLink',
|
||||
)}>
|
||||
<uui-box>
|
||||
${this.#renderLinkType()} ${this.#renderLinkAnchorInput()} ${this.#renderLinkTitleInput()}
|
||||
@@ -250,8 +341,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
<uui-button
|
||||
color="positive"
|
||||
look="primary"
|
||||
label=${this.localize.term(this.modalContext?.data.isNew ? 'general_add' : 'general_update')}
|
||||
?disabled=${!this.value.link.type}
|
||||
label=${this.localize.term(this.modalContext?.data?.isNew ? 'general_add' : 'general_update')}
|
||||
@click=${this.#onSubmit}></uui-button>
|
||||
</div>
|
||||
</umb-body-layout>
|
||||
@@ -263,7 +353,8 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
<umb-property-layout
|
||||
orientation=${this.#propertyLayoutOrientation}
|
||||
label=${this.localize.term('linkPicker_modalSource')}
|
||||
mandatory>
|
||||
mandatory
|
||||
?invalid=${this._missingLinkUrl}>
|
||||
<div slot="editor">
|
||||
${this.#renderLinkTypeSelection()} ${this.#renderDocumentPicker()} ${this.#renderMediaPicker()}
|
||||
${this.#renderLinkUrlInput()} ${this.#renderLinkUrlInputReadOnly()}
|
||||
@@ -326,9 +417,10 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
placeholder=${this.localize.term('placeholders_enterUrl')}
|
||||
.value=${this.value.link.url ?? ''}
|
||||
?disabled=${!!this.value.link.unique}
|
||||
?required=${this._config.hideAnchor}
|
||||
@change=${this.#onLinkUrlInput}
|
||||
${umbBindToValidation(this)}>
|
||||
required
|
||||
@input=${this.#onLinkUrlInput}
|
||||
${umbBindToValidation(this)}
|
||||
${umbFocus()}>
|
||||
${when(
|
||||
!this.value.link.unique,
|
||||
() => html`
|
||||
@@ -361,12 +453,10 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
<uui-input
|
||||
data-mark="input:anchor"
|
||||
slot="editor"
|
||||
id="link-anchor"
|
||||
label=${this.localize.term('placeholders_anchor')}
|
||||
placeholder=${this.localize.term('placeholders_anchor')}
|
||||
.value=${this.value.link.queryString ?? ''}
|
||||
@change=${this.#onLinkAnchorInput}
|
||||
${umbBindToValidation(this)}></uui-input>
|
||||
@change=${this.#onLinkAnchorInput}></uui-input>
|
||||
</umb-property-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ export class UmbEntityReferencesWorkspaceInfoAppElement extends UmbLitElement {
|
||||
if (!this._items?.length) return nothing;
|
||||
return html`
|
||||
<umb-workspace-info-app-layout headline="#references_labelUsedByItems">
|
||||
${this.#renderItems()} ${this.#renderReferencePagination()}
|
||||
<div id="content">${this.#renderItems()} ${this.#renderReferencePagination()}</div>
|
||||
</umb-workspace-info-app-layout>
|
||||
`;
|
||||
}
|
||||
@@ -144,6 +144,11 @@ export class UmbEntityReferencesWorkspaceInfoAppElement extends UmbLitElement {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
#content {
|
||||
display: block;
|
||||
padding: var(--uui-size-space-3) var(--uui-size-space-4);
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
Reference in New Issue
Block a user