@umbraco-cms/backoffice 17.7.0 → 17.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7430,6 +7430,7 @@ export type GetImagingResizeUrlsData = {
7430
7430
  path?: never;
7431
7431
  query?: {
7432
7432
  id?: Array<string>;
7433
+ dataTypeId?: string;
7433
7434
  height?: number;
7434
7435
  width?: number;
7435
7436
  mode?: ImageCropModeModel;
@@ -9571,6 +9572,7 @@ export type GetMediaUrlsData = {
9571
9572
  path?: never;
9572
9573
  query?: {
9573
9574
  id?: Array<string>;
9575
+ dataTypeId?: string;
9574
9576
  };
9575
9577
  url: '/umbraco/management/api/v1/media/urls';
9576
9578
  };
@@ -56,6 +56,7 @@ export declare class UmbMediaThumbnailElement extends UmbLitElement {
56
56
  externalLoading: boolean;
57
57
  private _isLoading;
58
58
  private _thumbnailUrl;
59
+ constructor();
59
60
  render(): import("lit-html").TemplateResult<1>;
60
61
  connectedCallback(): void;
61
62
  disconnectedCallback(): void;
@@ -11,6 +11,7 @@ import { UmbLitElement } from '../../../core/lit-element/index.js';
11
11
  import { UmbTextStyles } from '../../../core/style/index.js';
12
12
  import { UMB_ACTION_EVENT_CONTEXT } from '../../../core/action/index.js';
13
13
  import { UmbEntityUpdatedEvent } from '../../../core/entity-action/index.js';
14
+ import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '../../../content/content/index.js';
14
15
  /**
15
16
  * Displays a thumbnail for a media item, with optional server-side cropping and transparency support.
16
17
  * This is the recommended component for rendering media images in the backoffice.
@@ -20,8 +21,14 @@ import { UmbEntityUpdatedEvent } from '../../../core/entity-action/index.js';
20
21
  * @csspart img - The underlying `<img>` element.
21
22
  */
22
23
  let UmbMediaThumbnailElement = class UmbMediaThumbnailElement extends UmbLitElement {
24
+ #imagingRepository;
25
+ #intersectionObserver;
26
+ #actionEventContext;
27
+ #dataTypeUnique;
28
+ #hasRequestedThumbnail;
29
+ #latestRequest;
23
30
  constructor() {
24
- super(...arguments);
31
+ super();
25
32
  /**
26
33
  * The width of the thumbnail in pixels.
27
34
  * @default 300
@@ -59,15 +66,27 @@ let UmbMediaThumbnailElement = class UmbMediaThumbnailElement extends UmbLitElem
59
66
  this._isLoading = false;
60
67
  this._thumbnailUrl = '';
61
68
  this.#imagingRepository = new UmbImagingRepository(this);
69
+ this.#hasRequestedThumbnail = false;
70
+ this.#latestRequest = 0;
62
71
  this.#onEntityUpdated = (event) => {
63
72
  if (event.getUnique() === this.unique) {
64
73
  this.#generateThumbnailUrl();
65
74
  }
66
75
  };
76
+ // A picker configured to ignore user start nodes may reference media outside them,
77
+ // which the server only resolves when told which data type the request originates from.
78
+ this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => {
79
+ this.observe(context?.dataType, (dataType) => {
80
+ // The context is also lost when the element disconnects, which needs no new request.
81
+ if (!dataType?.unique)
82
+ return;
83
+ this.#dataTypeUnique = dataType.unique;
84
+ if (this.#hasRequestedThumbnail) {
85
+ this.#generateThumbnailUrl();
86
+ }
87
+ }, '_observeDataType');
88
+ });
67
89
  }
68
- #imagingRepository;
69
- #intersectionObserver;
70
- #actionEventContext;
71
90
  render() {
72
91
  return when(this.externalLoading || this._isLoading, () => this.#renderLoading(), () => this.#renderThumbnail());
73
92
  }
@@ -126,12 +145,18 @@ let UmbMediaThumbnailElement = class UmbMediaThumbnailElement extends UmbLitElem
126
145
  if (!this.unique)
127
146
  return;
128
147
  this._isLoading = true;
148
+ this.#hasRequestedThumbnail = true;
149
+ const request = ++this.#latestRequest;
129
150
  const { data } = await this.#imagingRepository.requestResizedItems([this.unique], {
130
151
  height: this.height,
131
152
  width: this.width,
132
153
  mode: this.mode,
133
154
  format: this.format,
155
+ dataTypeUnique: this.#dataTypeUnique,
134
156
  });
157
+ // A newer request (for example after the data type resolved) supersedes this one.
158
+ if (request !== this.#latestRequest)
159
+ return;
135
160
  this._thumbnailUrl = data?.[0]?.url ?? '';
136
161
  this._isLoading = false;
137
162
  }
@@ -23,7 +23,8 @@ export class UmbImagingServerDataSource {
23
23
  async getItems(uniques, imagingModel) {
24
24
  if (!uniques.length)
25
25
  throw new Error('Uniques are missing');
26
- const { data, error } = await tryExecute(this.#host, ImagingService.getImagingResizeUrls({ query: { id: uniques, ...imagingModel } }));
26
+ const { dataTypeUnique, ...resizeModel } = imagingModel ?? {};
27
+ const { data, error } = await tryExecute(this.#host, ImagingService.getImagingResizeUrls({ query: { id: uniques, ...resizeModel, dataTypeId: dataTypeUnique } }));
27
28
  if (data) {
28
29
  const items = data.map((item) => this.#mapper(item));
29
30
  return { data: items };
@@ -5,6 +5,11 @@ export interface UmbImagingResizeModel {
5
5
  width?: number;
6
6
  mode?: UmbImagingCropMode;
7
7
  format?: string;
8
+ /**
9
+ * The unique of the data type the request originates from, such as a media picker.
10
+ * Media outside the user's start nodes is only resolved when this data type ignores user start nodes.
11
+ */
12
+ dataTypeUnique?: string;
8
13
  }
9
14
  /**
10
15
  * Generates a cache key from an imaging resize configuration.
@@ -7,5 +7,5 @@ export { UmbImagingCropMode };
7
7
  * @returns {string} The cache key
8
8
  */
9
9
  export function generateImagingCacheKey(model) {
10
- return model ? `${model.width}x${model.height};${model.mode};${model.format}` : 'generic';
10
+ return model ? `${model.width}x${model.height};${model.mode};${model.format};${model.dataTypeUnique}` : 'generic';
11
11
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Returns the URL if it can be offered as a link, i.e. it resolves to an http or https location.
3
+ * @param {string | undefined} url - The media URL.
4
+ * @param {string} base - The base used to resolve relative URLs.
5
+ * @returns {string | undefined} The URL, or undefined if it must not be rendered as a link.
6
+ */
7
+ export declare function getLinkableMediaUrl(url: string | undefined, base?: string): string | undefined;
8
+ /**
9
+ * Renders an image preview on a checkerboard background into the given document.
10
+ * The image is referenced through an `<img>` element, so scripts embedded in an SVG do not run.
11
+ * @param {Document} document - The document to render into.
12
+ * @param {string} imageUrl - The URL of the image.
13
+ */
14
+ export declare function renderImagePreview(document: Document, imageUrl: string): void;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Returns the URL if it can be offered as a link, i.e. it resolves to an http or https location.
3
+ * @param {string | undefined} url - The media URL.
4
+ * @param {string} base - The base used to resolve relative URLs.
5
+ * @returns {string | undefined} The URL, or undefined if it must not be rendered as a link.
6
+ */
7
+ export function getLinkableMediaUrl(url, base = window.location.href) {
8
+ if (!url)
9
+ return undefined;
10
+ try {
11
+ const { protocol } = new URL(url, base);
12
+ return protocol === 'http:' || protocol === 'https:' ? url : undefined;
13
+ }
14
+ catch {
15
+ return undefined;
16
+ }
17
+ }
18
+ /**
19
+ * Renders an image preview on a checkerboard background into the given document.
20
+ * The image is referenced through an `<img>` element, so scripts embedded in an SVG do not run.
21
+ * @param {Document} document - The document to render into.
22
+ * @param {string} imageUrl - The URL of the image.
23
+ */
24
+ export function renderImagePreview(document, imageUrl) {
25
+ const body = document.body ?? document.documentElement.appendChild(document.createElement('body'));
26
+ body.style.backgroundImage =
27
+ 'linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(135deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(135deg, transparent 75%, #ccc 75%)';
28
+ body.style.backgroundSize = '30px 30px';
29
+ body.style.backgroundPosition = '0 0, 15px 0, 15px -15px, 0px 15px';
30
+ const image = document.createElement('img');
31
+ image.src = imageUrl;
32
+ body.replaceChildren(image);
33
+ }
@@ -6,11 +6,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { UmbMediaUrlRepository } from '../repository/index.js';
8
8
  import { UMB_MEDIA_WORKSPACE_CONTEXT } from '../../workspace/constants.js';
9
+ import { getLinkableMediaUrl, renderImagePreview } from './media-link.function.js';
9
10
  import { css, customElement, html, nothing, repeat, state, when } from '../../../../../external/lit/index.js';
10
11
  import { UmbLitElement } from '../../../../core/lit-element/index.js';
11
12
  import { UmbRequestReloadStructureForEntityEvent } from '../../../../core/entity-action/index.js';
12
13
  import { observeMultiple } from '../../../../../libs/observable-api/index.js';
13
- import { debounce, sanitizeHTML } from '../../../../core/utils/index.js';
14
+ import { debounce } from '../../../../core/utils/index.js';
14
15
  let UmbMediaLinksWorkspaceInfoAppElement = class UmbMediaLinksWorkspaceInfoAppElement extends UmbLitElement {
15
16
  #mediaUrlRepository;
16
17
  #urls;
@@ -80,14 +81,11 @@ let UmbMediaLinksWorkspaceInfoAppElement = class UmbMediaLinksWorkspaceInfoAppEl
80
81
  const popup = window.open('', '_blank');
81
82
  if (!popup)
82
83
  return;
83
- const html = `<!doctype html>
84
- <body style="background-image: linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(135deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(135deg, transparent 75%, #ccc 75%); background-size:30px 30px; background-position:0 0, 15px 0, 15px -15px, 0px 15px;">
85
- <img src="${imagePath}"/>
86
- <script>history.pushState(null, null, "${sanitizeHTML(window.location.href)}");</script>
87
- </body>`;
84
+ // Re-opening the document gives it this document's URL, without which the popup cannot push a history state for it.
88
85
  popup.document.open();
89
- popup.document.write(html);
90
86
  popup.document.close();
87
+ renderImagePreview(popup.document, imagePath);
88
+ popup.history.pushState(null, '', window.location.href);
91
89
  }
92
90
  #renderContent() {
93
91
  if (this._links.length) {
@@ -106,19 +104,27 @@ let UmbMediaLinksWorkspaceInfoAppElement = class UmbMediaLinksWorkspaceInfoAppEl
106
104
  #renderLinkItem(item) {
107
105
  if (!item.url)
108
106
  return nothing;
109
- const ext = item.url.split(/[#?]/)[0].split('.').pop()?.trim().toLowerCase();
110
- if (ext === 'svg') {
107
+ const url = getLinkableMediaUrl(item.url);
108
+ if (!url) {
111
109
  return html `
112
- <a href="#" target="_blank" class="link-item with-href" @click=${() => this.#openSvg(item.url)}>
110
+ <div class="link-item">
113
111
  <span class="link-content">${item.url}</span>
112
+ </div>
113
+ `;
114
+ }
115
+ const ext = url.split(/[#?]/)[0].split('.').pop()?.trim().toLowerCase();
116
+ if (ext === 'svg') {
117
+ return html `
118
+ <a href="#" target="_blank" class="link-item with-href" @click=${() => this.#openSvg(url)}>
119
+ <span class="link-content">${url}</span>
114
120
  <uui-icon name="icon-out"></uui-icon>
115
121
  </a>
116
122
  `;
117
123
  }
118
124
  else {
119
125
  return html `
120
- <a href=${item.url} target="_blank" class="link-item with-href">
121
- <span class="link-content">${item.url}</span>
126
+ <a href=${url} target="_blank" class="link-item with-href">
127
+ <span class="link-content">${url}</span>
122
128
  <uui-icon name="icon-out"></uui-icon>
123
129
  </a>
124
130
  `;
@@ -8,11 +8,7 @@ import { UmbItemServerDataSourceBase } from '../../../../core/repository/index.j
8
8
  * @augments {UmbItemServerDataSourceBase}
9
9
  */
10
10
  export declare class UmbMediaUrlServerDataSource extends UmbItemServerDataSourceBase<MediaUrlInfoResponseModel, UmbMediaUrlModel> {
11
- /**
12
- * Creates an instance of UmbMediaUrlServerDataSource.
13
- * @param {UmbControllerHost} host - The controller host for this controller to be appended to
14
- * @memberof UmbMediaUrlServerDataSource
15
- */
11
+ #private;
16
12
  constructor(host: UmbControllerHost);
17
13
  getItems(uniques: Array<string>): Promise<{
18
14
  data: UmbMediaUrlModel[] | undefined;
@@ -1,6 +1,7 @@
1
1
  import { UmbItemDataApiGetRequestController } from '../../../../core/entity-item/index.js';
2
2
  import { MediaService } from '../../../../core/backend-api/index.js';
3
3
  import { UmbItemServerDataSourceBase } from '../../../../core/repository/index.js';
4
+ import { UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT } from '../../../../content/content/index.js';
4
5
  /**
5
6
  * A server data source for Media Urls
6
7
  * @class UmbMediaUrlServerDataSource
@@ -12,17 +13,25 @@ export class UmbMediaUrlServerDataSource extends UmbItemServerDataSourceBase {
12
13
  * @param {UmbControllerHost} host - The controller host for this controller to be appended to
13
14
  * @memberof UmbMediaUrlServerDataSource
14
15
  */
16
+ #dataTypeUnique;
15
17
  constructor(host) {
16
18
  super(host, {
17
19
  mapper,
18
20
  });
21
+ // A picker configured to ignore user start nodes may reference media outside them,
22
+ // which the server only resolves when told which data type the request originates from.
23
+ this.consumeContext(UMB_PROPERTY_TYPE_BASED_PROPERTY_CONTEXT, (context) => {
24
+ this.observe(context?.dataType, (dataType) => {
25
+ this.#dataTypeUnique = dataType?.unique;
26
+ }, '_observeDataType');
27
+ });
19
28
  }
20
29
  async getItems(uniques) {
21
30
  if (!uniques)
22
31
  throw new Error('Uniques are missing');
23
32
  const itemRequestManager = new UmbItemDataApiGetRequestController(this, {
24
33
  // eslint-disable-next-line local-rules/no-direct-api-import
25
- api: (args) => MediaService.getMediaUrls({ query: { id: args.uniques } }),
34
+ api: (args) => MediaService.getMediaUrls({ query: { id: args.uniques, dataTypeId: this.#dataTypeUnique } }),
26
35
  uniques,
27
36
  });
28
37
  const { data, error } = await itemRequestManager.request();
@@ -237,7 +237,7 @@ let UmbInputMultiUrlElement = class UmbInputMultiUrlElement extends UmbFormContr
237
237
  }
238
238
  async #getUrlForMedia(unique) {
239
239
  const { data } = await this.#mediaUrlRepository.requestItems([unique]);
240
- return data?.[0].url ?? '';
240
+ return data?.[0]?.url ?? '';
241
241
  }
242
242
  async #getNameForDocument(unique) {
243
243
  const { data } = await this.#documentItemRepository.requestItems([unique]);
@@ -1,19 +1,24 @@
1
1
  import { attachLinkInterceptor } from '../utils/index.js';
2
2
  import { UmbPreviewRepository } from '../repository/index.js';
3
+ import { UmbPreviewSessionRenewalController } from '../controllers/preview-session-renewal.controller.js';
3
4
  import { UMB_PREVIEW_CONTEXT } from './preview.context-token.js';
4
5
  import { HubConnectionBuilder, HttpTransportType } from '../../../external/signalr/index.js';
5
6
  import { UmbBooleanState, UmbStringState } from '../../../libs/observable-api/index.js';
6
7
  import { UmbContextBase } from '../../../libs/class-api/index.js';
7
8
  import { UmbLocalizationController } from '../../../libs/localization-api/index.js';
9
+ import { UMB_AUTH_CONTEXT } from '../../core/auth/index.js';
8
10
  import { UMB_NOTIFICATION_CONTEXT } from '../../core/notification/index.js';
9
11
  import { UMB_SERVER_CONTEXT } from '../../core/server/index.js';
10
12
  export class UmbPreviewContext extends UmbContextBase {
13
+ #authContext;
11
14
  #connection;
12
15
  #currentArgs;
13
16
  #notificationContext;
14
17
  #resizeController;
18
+ #serverContext;
15
19
  #serverUrl;
16
20
  #previewRepository;
21
+ #previewSessionRenewal;
17
22
  #localize;
18
23
  #culture;
19
24
  #iframeReady;
@@ -25,6 +30,7 @@ export class UmbPreviewContext extends UmbContextBase {
25
30
  this.#currentArgs = {};
26
31
  this.#serverUrl = '';
27
32
  this.#previewRepository = new UmbPreviewRepository(this);
33
+ this.#previewSessionRenewal = new UmbPreviewSessionRenewalController(this, this.#previewRepository);
28
34
  this.#localize = new UmbLocalizationController(this);
29
35
  this.#culture = new UmbStringState(undefined);
30
36
  this.culture = this.#culture.asObservable();
@@ -53,8 +59,16 @@ export class UmbPreviewContext extends UmbContextBase {
53
59
  return;
54
60
  }
55
61
  this.#serverUrl = serverUrl;
62
+ this.#serverContext = serverContext;
56
63
  this.#setPreviewUrl({ serverUrl });
57
- this.#initHubConnection(serverUrl, serverContext);
64
+ this.#initHubConnection();
65
+ });
66
+ this.consumeContext(UMB_AUTH_CONTEXT, (authContext) => {
67
+ this.#authContext = authContext;
68
+ this.#initHubConnection();
69
+ if (authContext) {
70
+ this.#previewSessionRenewal.observeSession(authContext.session$, () => this.#getPreviewSessionArgs());
71
+ }
58
72
  });
59
73
  this.consumeContext(UMB_NOTIFICATION_CONTEXT, (notificationContext) => {
60
74
  this.#notificationContext = notificationContext;
@@ -70,22 +84,28 @@ export class UmbPreviewContext extends UmbContextBase {
70
84
  this.#connection = undefined;
71
85
  }
72
86
  }
73
- async #initHubConnection(serverUrl, serverContext) {
74
- const previewHubUrl = `${serverUrl}/umbraco/PreviewHub`;
87
+ async #initHubConnection() {
88
+ const authContext = this.#authContext;
89
+ if (!authContext || !this.#serverUrl)
90
+ return;
91
+ const previewHubUrl = `${this.#serverUrl}/umbraco/PreviewHub`;
75
92
  // Make sure that no previous connection exists.
76
93
  if (this.#connection) {
77
94
  await this.#connection.stop();
78
95
  this.#connection = undefined;
79
96
  }
80
- const skipNegotiation = serverContext?.getServerConnection()?.getSignalRSkipNegotiation() ?? false;
81
- const hubOptions = {};
97
+ const skipNegotiation = this.#serverContext?.getServerConnection()?.getSignalRSkipNegotiation() ?? false;
98
+ const hubOptions = {
99
+ accessTokenFactory: () => authContext.getLatestToken(),
100
+ };
82
101
  if (skipNegotiation) {
83
102
  hubOptions.skipNegotiation = true;
84
103
  hubOptions.transport = HttpTransportType.WebSockets;
85
104
  }
86
105
  this.#connection = new HubConnectionBuilder().withUrl(previewHubUrl, hubOptions).build();
87
- this.#connection.on('refreshed', (payload) => {
106
+ this.#connection.on('refreshed', async (payload) => {
88
107
  if (payload === this.#unique.getValue()) {
108
+ await this.#previewSessionRenewal.renew(this.#getPreviewSessionArgs());
89
109
  this.#setPreviewUrl({ rnd: Math.random() });
90
110
  }
91
111
  });
@@ -110,6 +130,13 @@ export class UmbPreviewContext extends UmbContextBase {
110
130
  });
111
131
  }
112
132
  }
133
+ #getPreviewSessionArgs() {
134
+ return {
135
+ unique: this.#unique.getValue(),
136
+ culture: this.#culture.getValue(),
137
+ segment: this.#segment.getValue(),
138
+ };
139
+ }
113
140
  async #getPublishedUrl() {
114
141
  const unique = this.#unique.getValue();
115
142
  if (!unique)
@@ -0,0 +1,35 @@
1
+ import { UmbPreviewRepository } from '../repository/preview.repository.js';
2
+ import { UmbControllerBase } from '../../../libs/class-api/index.js';
3
+ import type { Observable } from '../../../external/rxjs/index.js';
4
+ import type { UmbControllerHost } from '../../../libs/controller-api/index.js';
5
+ export interface UmbPreviewSessionRenewalArgs {
6
+ unique?: string;
7
+ culture?: string;
8
+ segment?: string;
9
+ }
10
+ /**
11
+ * Keeps the website preview session alive for as long as the back-office session is, by asking the server to
12
+ * renew it whenever the back-office session is renewed.
13
+ */
14
+ export declare class UmbPreviewSessionRenewalController extends UmbControllerBase {
15
+ #private;
16
+ /**
17
+ * Creates a new {@link UmbPreviewSessionRenewalController}.
18
+ * @param {UmbControllerHost} host - The controller host.
19
+ * @param {UmbPreviewRepository} [previewRepository] - Optional repository override; defaults to a new
20
+ * {@link UmbPreviewRepository}. Intended for testing.
21
+ */
22
+ constructor(host: UmbControllerHost, previewRepository?: UmbPreviewRepository);
23
+ /**
24
+ * Renews the preview session each time the given back-office session emits a live session.
25
+ * @param {Observable<unknown>} session - The back-office session; emits a falsy value when there is no session.
26
+ * @param {() => UmbPreviewSessionRenewalArgs} getArgs - Provides the document currently being previewed.
27
+ */
28
+ observeSession(session: Observable<unknown>, getArgs: () => UmbPreviewSessionRenewalArgs): void;
29
+ /**
30
+ * Renews the preview session for the given document.
31
+ * @param {UmbPreviewSessionRenewalArgs} args - The document currently being previewed.
32
+ * @returns {Promise<void>} Resolves once the renewal has completed or failed.
33
+ */
34
+ renew(args: UmbPreviewSessionRenewalArgs): Promise<void>;
35
+ }
@@ -0,0 +1,49 @@
1
+ import { UmbPreviewRepository } from '../repository/preview.repository.js';
2
+ import { UmbControllerBase } from '../../../libs/class-api/index.js';
3
+ // The preview app always previews through the built-in document URL provider, whose preview URL is internal
4
+ // and so (re)starts the preview session on the server.
5
+ const UMB_PREVIEW_SESSION_URL_PROVIDER_ALIAS = 'umbDocumentUrlProvider';
6
+ /**
7
+ * Keeps the website preview session alive for as long as the back-office session is, by asking the server to
8
+ * renew it whenever the back-office session is renewed.
9
+ */
10
+ export class UmbPreviewSessionRenewalController extends UmbControllerBase {
11
+ #previewRepository;
12
+ /**
13
+ * Creates a new {@link UmbPreviewSessionRenewalController}.
14
+ * @param {UmbControllerHost} host - The controller host.
15
+ * @param {UmbPreviewRepository} [previewRepository] - Optional repository override; defaults to a new
16
+ * {@link UmbPreviewRepository}. Intended for testing.
17
+ */
18
+ constructor(host, previewRepository) {
19
+ super(host);
20
+ this.#previewRepository = previewRepository ?? new UmbPreviewRepository(this);
21
+ }
22
+ /**
23
+ * Renews the preview session each time the given back-office session emits a live session.
24
+ * @param {Observable<unknown>} session - The back-office session; emits a falsy value when there is no session.
25
+ * @param {() => UmbPreviewSessionRenewalArgs} getArgs - Provides the document currently being previewed.
26
+ */
27
+ observeSession(session, getArgs) {
28
+ this.observe(session, (value) => {
29
+ if (value) {
30
+ this.renew(getArgs());
31
+ }
32
+ }, '_observePreviewSession');
33
+ }
34
+ /**
35
+ * Renews the preview session for the given document.
36
+ * @param {UmbPreviewSessionRenewalArgs} args - The document currently being previewed.
37
+ * @returns {Promise<void>} Resolves once the renewal has completed or failed.
38
+ */
39
+ async renew(args) {
40
+ if (!args.unique)
41
+ return;
42
+ try {
43
+ await this.#previewRepository.getPreviewUrl(args.unique, UMB_PREVIEW_SESSION_URL_PROVIDER_ALIAS, args.culture, args.segment);
44
+ }
45
+ catch {
46
+ // The preview carries on with its current session until that expires.
47
+ }
48
+ }
49
+ }