Skip to content

Commit

Permalink
Feature: Document Workspace Info reload components (#2492)
Browse files Browse the repository at this point in the history
* Adds Document URL Repository

* Extracts Document Workspace Info Links to its own component

Refactored to use the new Document URL Repository.

Plus other housekeeping on the main Document Workspace Info component.

* Refactored Document Workspace Info History component

to listen for the "Request Reload Structure" event

* Refactored Document Workspace Info Reference component
  • Loading branch information
leekelleher authored Oct 29, 2024
1 parent 647ed15 commit 0d1b21e
Show file tree
Hide file tree
Showing 15 changed files with 391 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export class UmbHistoryItemElement extends UmbLitElement {
.user-info div {
display: flex;
flex-direction: column;
min-width: var(--uui-size-60);
}
.detail {
Expand Down
1 change: 1 addition & 0 deletions src/packages/documents/documents/repository/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { UmbDocumentDetailRepository, UMB_DOCUMENT_DETAIL_REPOSITORY_ALIAS } from './detail/index.js';
export { UmbDocumentItemRepository, UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS } from './item/index.js';
export { UmbDocumentPublishingRepository, UMB_DOCUMENT_PUBLISHING_REPOSITORY_ALIAS } from './publishing/index.js';
export { UmbDocumentUrlRepository, UMB_DOCUMENT_URL_REPOSITORY_ALIAS } from './url/index.js';
export { UmbDocumentPreviewRepository } from './preview/index.js';

export type { UmbDocumentItemModel } from './item/types.js';
8 changes: 7 additions & 1 deletion src/packages/documents/documents/repository/manifests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { manifests as detailManifests } from './detail/manifests.js';
import { manifests as itemManifests } from './item/manifests.js';
import { manifests as publishingManifests } from './publishing/manifests.js';
import { manifests as urlManifests } from './url/manifests.js';

export const manifests: Array<UmbExtensionManifest> = [...detailManifests, ...itemManifests, ...publishingManifests];
export const manifests: Array<UmbExtensionManifest> = [
...detailManifests,
...itemManifests,
...publishingManifests,
...urlManifests,
];
2 changes: 2 additions & 0 deletions src/packages/documents/documents/repository/url/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const UMB_DOCUMENT_URL_REPOSITORY_ALIAS = 'Umb.Repository.Document.Url';
export const UMB_DOCUMENT_URL_STORE_ALIAS = 'Umb.Store.Document.Url';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { UmbDocumentUrlsModel } from './types.js';
import { UMB_DOCUMENT_URL_STORE_CONTEXT } from './document-url.store.context-token.js';
import { UmbDocumentUrlServerDataSource } from './document-url.server.data-source.js';
import { UmbItemRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

export class UmbDocumentUrlRepository extends UmbItemRepositoryBase<UmbDocumentUrlsModel> {
constructor(host: UmbControllerHost) {
super(host, UmbDocumentUrlServerDataSource, UMB_DOCUMENT_URL_STORE_CONTEXT);
}
}

export { UmbDocumentUrlRepository as api };
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { UmbDocumentUrlsModel } from './types.js';
import { DocumentService } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbItemServerDataSourceBase } from '@umbraco-cms/backoffice/repository';
import type { DocumentUrlInfoResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

/**
* A server data source for Document URLs
* @class UmbDocumentUrlServerDataSource
* @implements {DocumentTreeDataSource}
*/
export class UmbDocumentUrlServerDataSource extends UmbItemServerDataSourceBase<
DocumentUrlInfoResponseModel,
UmbDocumentUrlsModel
> {
/**
* Creates an instance of UmbDocumentUrlServerDataSource.
* @param {UmbControllerHost} host - The controller host for this controller to be appended to
* @memberof UmbDocumentUrlServerDataSource
*/
constructor(host: UmbControllerHost) {
super(host, { getItems, mapper });
}
}

/* eslint-disable local-rules/no-direct-api-import */
const getItems = (uniques: Array<string>) => DocumentService.getDocumentUrls({ id: uniques });

const mapper = (item: DocumentUrlInfoResponseModel): UmbDocumentUrlsModel => ({ unique: item.id, urls: item.urlInfos });
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type UmbDocumentUrlStore from './document-url.store.js';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';

export const UMB_DOCUMENT_URL_STORE_CONTEXT = new UmbContextToken<UmbDocumentUrlStore>('UmbDocumentUrlStore');
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { UmbDocumentDetailModel } from '../../types.js';
import { UMB_DOCUMENT_URL_STORE_CONTEXT } from './document-url.store.context-token.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbItemStoreBase } from '@umbraco-cms/backoffice/store';

/**
* @class UmbDocumentUrlStore
* @augments {UmbStoreBase}
* @description - Data Store for Document URLs
*/

export class UmbDocumentUrlStore extends UmbItemStoreBase<UmbDocumentDetailModel> {
/**
* Creates an instance of UmbDocumentUrlStore.
* @param {UmbControllerHost} host - The controller host for this controller to be appended to
* @memberof UmbDocumentUrlStore
*/
constructor(host: UmbControllerHost) {
super(host, UMB_DOCUMENT_URL_STORE_CONTEXT.toString());
}
}

export default UmbDocumentUrlStore;
2 changes: 2 additions & 0 deletions src/packages/documents/documents/repository/url/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { UmbDocumentUrlRepository } from './document-url.repository.js';
export { UMB_DOCUMENT_URL_REPOSITORY_ALIAS } from './constants.js';
18 changes: 18 additions & 0 deletions src/packages/documents/documents/repository/url/manifests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { UMB_DOCUMENT_URL_REPOSITORY_ALIAS, UMB_DOCUMENT_URL_STORE_ALIAS } from './constants.js';
import type { ManifestItemStore, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';

const urlRepository: ManifestRepository = {
type: 'repository',
alias: UMB_DOCUMENT_URL_REPOSITORY_ALIAS,
name: 'Document Url Repository',
api: () => import('./document-url.repository.js'),
};

const urlStore: ManifestItemStore = {
type: 'itemStore',
alias: UMB_DOCUMENT_URL_STORE_ALIAS,
name: 'Document Url Store',
api: () => import('./document-url.store.js'),
};

export const manifests = [urlRepository, urlStore];
9 changes: 9 additions & 0 deletions src/packages/documents/documents/repository/url/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface UmbDocumentUrlsModel {
unique: string;
urls: Array<UmbDocumentUrlModel>;
}

export interface UmbDocumentUrlModel {
culture?: string | null;
url?: string;
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,65 @@
import type { UmbDocumentAuditLogModel } from '../../../audit-log/types.js';
import { UmbDocumentAuditLogRepository } from '../../../audit-log/index.js';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../document-workspace.context-token.js';
import { TimeOptions, getDocumentHistoryTagStyleAndText } from './utils.js';
import { css, html, customElement, state, nothing, repeat } from '@umbraco-cms/backoffice/external/lit';
import { getDocumentHistoryTagStyleAndText, TimeOptions } from './utils.js';
import { css, customElement, html, nothing, repeat, state, when } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbPaginationManager } from '@umbraco-cms/backoffice/utils';
import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbUserItemModel } from '@umbraco-cms/backoffice/user';
import { UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbUserItemRepository } from '@umbraco-cms/backoffice/user';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import type { ManifestEntityAction } from '@umbraco-cms/backoffice/entity-action';
import type { UmbUserItemModel } from '@umbraco-cms/backoffice/user';
import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';

@customElement('umb-document-workspace-view-info-history')
export class UmbDocumentWorkspaceViewInfoHistoryElement extends UmbLitElement {
@state()
_currentPageNumber = 1;
#allowedActions = new Set(['Umb.EntityAction.Document.Rollback']);

@state()
_totalPages = 1;

@state()
private _items: Array<UmbDocumentAuditLogModel> = [];

#workspaceContext?: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE;
#auditLogRepository = new UmbDocumentAuditLogRepository(this);

#pagination = new UmbPaginationManager();

#userItemRepository = new UmbUserItemRepository(this);

#userMap = new Map<string, UmbUserItemModel>();

#workspaceContext?: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE;

@state()
private _currentPageNumber = 1;

@state()
private _items: Array<UmbDocumentAuditLogModel> = [];

@state()
private _totalPages = 1;

constructor() {
super();

this.#pagination.setPageSize(10);
this.observe(this.#pagination.currentPage, (number) => (this._currentPageNumber = number));
this.observe(this.#pagination.totalPages, (number) => (this._totalPages = number));

this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (context) => {
context.addEventListener(UmbRequestReloadStructureForEntityEvent.TYPE, () => {
this.#requestAuditLogs();
});
});

this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (instance) => {
this.#workspaceContext = instance;
this.#requestAuditLogs();
});
}

#onPageChange(event: UUIPaginationEvent) {
this.#pagination.setCurrentPageNumber(event.target?.current);
this.#requestAuditLogs();
}

async #requestAuditLogs() {
const unique = this.#workspaceContext?.getUnique();
if (!unique) throw new Error('Document unique is required');
Expand All @@ -58,11 +77,6 @@ export class UmbDocumentWorkspaceViewInfoHistoryElement extends UmbLitElement {
}
}

#onPageChange(event: UUIPaginationEvent) {
this.#pagination.setCurrentPageNumber(event.target?.current);
this.#requestAuditLogs();
}

async #requestAndCacheUserItems() {
const allUsers = this._items?.map((item) => item.user.unique).filter(Boolean) as string[];
const uniqueUsers = [...new Set(allUsers)];
Expand All @@ -83,90 +97,84 @@ export class UmbDocumentWorkspaceViewInfoHistoryElement extends UmbLitElement {
}

override render() {
return html`<uui-box>
<umb-localize slot="headline" key="general_history">History</umb-localize>
<umb-extension-with-api-slot
return html`
<uui-box headline=${this.localize.term('general_history')}>
<umb-extension-with-api-slot
slot="header-actions"
type="entityAction"
.filter=${(manifest: any) => manifest.alias === 'Umb.EntityAction.Document.Rollback'}></umb-extension-with-api-slot>
.filter=${(manifest: ManifestEntityAction) => this.#allowedActions.has(manifest.alias)}></umb-extension-with-api-slot>
</uui-button>
${this._items ? this.#renderHistory() : html`<uui-loader-circle></uui-loader-circle> `}
${when(
this._items,
() => this.#renderHistory(),
() => html`<div id="loader"><uui-loader></uui-loader></div>`,
)}
${this.#renderPagination()}
</uui-box> `;
</uui-box>
`;
}

#renderHistory() {
if (this._items && this._items.length) {
return html`
<umb-history-list>
${repeat(
this._items,
(item) => item.timestamp,
(item) => {
const { text, style } = getDocumentHistoryTagStyleAndText(item.logType);
const user = this.#userMap.get(item.user.unique);
return html`<umb-history-item
if (!this._items?.length) return html`${this.localize.term('content_noItemsToShow')}`;
return html`
<umb-history-list>
${repeat(
this._items,
(item) => item.timestamp,
(item) => {
const { text, style } = getDocumentHistoryTagStyleAndText(item.logType);
const user = this.#userMap.get(item.user.unique);
return html`
<umb-history-item
.name=${user?.name ?? 'Unknown'}
.detail=${this.localize.date(item.timestamp, TimeOptions)}>
<umb-user-avatar
slot="avatar"
.name=${user?.name}
.kind=${user?.kind}
.imgUrls=${user?.avatarUrls ?? []}></umb-user-avatar>
<span class="log-type">
.imgUrls=${user?.avatarUrls ?? []}>
</umb-user-avatar>
<div class="log-type">
<uui-tag look=${style.look} color=${style.color}>
${this.localize.term(text.label, item.parameters)}
</uui-tag>
${this.localize.term(text.desc, item.parameters)}
</span>
</umb-history-item>`;
},
)}
</umb-history-list>
`;
} else {
return html`${this.localize.term('content_noItemsToShow')}`;
}
<span>${this.localize.term(text.desc, item.parameters)}</span>
</div>
</umb-history-item>
`;
},
)}
</umb-history-list>
`;
}

#renderPagination() {
if (this._totalPages <= 1) return nothing;
return html`
${this._totalPages > 1
? html`
<uui-pagination
class="pagination"
.current=${this._currentPageNumber}
.total=${this._totalPages}
@change=${this.#onPageChange}></uui-pagination>
`
: nothing}
<uui-pagination
.current=${this._currentPageNumber}
.total=${this._totalPages}
@change=${this.#onPageChange}></uui-pagination>
`;
}

static override styles = [
UmbTextStyles,
css`
uui-loader-circle {
font-size: 2rem;
}
uui-tag uui-icon {
margin-right: var(--uui-size-space-1);
#loader {
display: flex;
justify-content: center;
}
.log-type {
flex-grow: 1;
gap: var(--uui-size-space-2);
display: grid;
grid-template-columns: var(--uui-size-40) auto;
gap: var(--uui-size-layout-1);
}
uui-pagination {
flex: 1;
display: inline-block;
}
.pagination {
display: flex;
justify-content: center;
margin-top: var(--uui-size-layout-1);
Expand Down
Loading

0 comments on commit 0d1b21e

Please sign in to comment.