diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-item.element.ts new file mode 100644 index 0000000000..1db73bb340 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-item.element.ts @@ -0,0 +1,97 @@ +import { css, html } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement, property } from 'lit/decorators.js'; +import { UmbLitElement } from '@umbraco-cms/element'; + +@customElement('umb-history-item') +export class UmbHistoryItemElement extends UmbLitElement { + static styles = [ + UUITextStyles, + css` + :host { + --avatar-size: calc(2em + 4px); + display: block; + } + + #wrapper { + display: flex; + width: 100%; + gap: calc(2 * var(--uui-size-space-5)); + align-items: center; + } + .slots-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + flex: 1; + } + + slot[name='actions'] { + --uui-button-border-radius: 50px 50px 50px 50px; + display: flex; + align-items: center; + --uui-button-height: calc(var(--uui-size-2) * 4); + margin-right: var(--uui-size-2); + } + #actions-container { + opacity: 0; + transition: opacity 120ms; + } + :host(:hover) #actions-container { + opacity: 1; + } + + :host(:hover) #actions-container { + opacity: 1; + } + + .user-info { + display: flex; + align-items: flex-end; + gap: var(--uui-size-space-5); + } + .user-info div { + display: flex; + flex-direction: column; + } + .detail { + font-size: var(--uui-size-4); + color: var(--uui-color-text-alt); + line-height: 1; + } + `, + ]; + + @property({ type: String }) + src?: string; + + @property({ type: String }) + name?: string; + + @property({ type: String }) + detail?: string; + + render() { + return html`
+
+ +
+ ${this.name} + ${this.detail} +
+
+
+ + +
+
`; + } +} + +export default UmbHistoryItemElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-history-item': UmbHistoryItemElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.element.ts new file mode 100644 index 0000000000..c89a0f39d5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.element.ts @@ -0,0 +1,49 @@ +import { css, html } from 'lit'; +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { customElement } from 'lit/decorators.js'; +import { UmbLitElement } from '@umbraco-cms/element'; + +@customElement('umb-history-list') +export class UmbHistoryListElement extends UmbLitElement { + static styles = [ + UUITextStyles, + css` + :host { + display: block; + --avatar-size: calc(2em + 4px); + } + + ::slotted(*) { + position: relative; + } + + ::slotted(*:not(:last-child)) { + margin-bottom: calc(2 * var(--uui-size-space-3)); + } + + ::slotted(*:not(:last-child))::before { + content: ''; + border: 1px solid var(--uui-color-border); + position: absolute; + display: block; + height: calc(1.5 * var(--avatar-size)); + top: var(--avatar-size); + left: calc(-1px + var(--avatar-size) / 2); + } + `, + ]; + + render() { + return html`
+ +
`; + } +} + +export default UmbHistoryListElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-history-list': UmbHistoryListElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.stories.ts new file mode 100644 index 0000000000..fdc13cc6e0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/history/history-list.stories.ts @@ -0,0 +1,37 @@ +import './history-list.element'; +import './history-item.element'; + +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + +import type { UmbHistoryListElement } from './history-list.element'; +import type { UmbHistoryItemElement } from './history-item.element'; + +export default { + title: 'Components/History UI', + component: 'umb-history-list', + id: 'umb-history-list', +} as Meta; + +export const AAAOverview: Story = () => html` + + Default slot + Action slot + + + Default slot + Action slot + + + Default slot + Action slot + +`; +AAAOverview.storyName = 'Overview'; + +export const Node: Story = () => html` + Default slot + Action slot +`; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts index e72f6bd7cf..58f9694311 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts @@ -31,6 +31,10 @@ import './table/table.element'; import './tree/tree.element'; import './variantable-property/variantable-property.element'; import './workspace/workspace-action-menu/workspace-action-menu.element'; + +import './history/history-list.element'; +import './history/history-item.element'; + import './workspace/workspace-action/workspace-action.element'; import './workspace/workspace-content/workspace-content.element'; import './workspace/workspace-layout/workspace-layout.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/info/workspace-view-content-info.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/info/workspace-view-content-info.element.ts index 3299a3d858..3a884755fb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/info/workspace-view-content-info.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-content/views/info/workspace-view-content-info.element.ts @@ -1,26 +1,191 @@ -import { css, html } from 'lit'; +import { css, html, nothing } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { repeat } from 'lit/directives/repeat.js'; import { customElement, state } from 'lit/decorators.js'; +import { UUIPaginationEvent } from '@umbraco-ui/uui'; import { UmbWorkspaceEntityContextInterface } from '../../../workspace-context/workspace-entity-context.interface'; import type { DocumentModel } from '@umbraco-cms/backend-api'; import { UmbLitElement } from '@umbraco-cms/element'; +interface HistoryNode { + userId?: number; + userAvatars?: []; + userName?: string; + timestamp?: string; + comment?: string; + entityType?: string; + logType?: HistoryLogType; + nodeId?: string; + parameters?: string; +} + +type HistoryLogType = 'Publish' | 'Save' | 'Unpublish' | 'ContentVersionEnableCleanup' | 'ContentVersionPreventCleanup'; + @customElement('umb-workspace-view-content-info') export class UmbWorkspaceViewContentInfoElement extends UmbLitElement { static styles = [ UUITextStyles, css` :host { - display: block; + display: grid; + gap: var(--uui-size-layout-1); margin: var(--uui-size-layout-1); + grid-template-columns: 1fr 350px; + } + + div.container { + display: flex; + flex-direction: column; + gap: var(--uui-size-layout-1); + } + + //General section + + #general-section { + display: flex; + flex-direction: column; + } + + .general-item { + display: flex; + flex-direction: column; + gap: var(--uui-size-space-1); + } + + .general-item:not(:last-child) { + margin-bottom: var(--uui-size-space-6); + } + + // Link section + + #link-section { + display: flex; + flex-direction: column; + text-align: left; + } + + .link-item { + padding: var(--uui-size-space-4) var(--uui-size-space-6); + display: grid; + grid-template-columns: 75px 1fr; + color: inherit; + text-decoration: none; + } + + .link-language { + color: var(--uui-color-divider-emphasis); + } + + .link-content.italic { + font-style: italic; + } + + .link-item uui-icon { + margin-right: var(--uui-size-space-2); + vertical-align: middle; + } + + .link-item.with-href { + cursor: pointer; + } + + .link-item.with-href:hover { + background: var(--uui-color-divider); + } + + //History section + + uui-tag uui-icon { + margin-right: var(--uui-size-space-1); + } + + .log-type { + display: flex; + gap: var(--uui-size-space-2); + } + uui-pagination { + display: inline-block; + } + .pagination { + display: flex; + justify-content: center; + margin-top: var(--uui-size-space-4); } `, ]; + @state() + private _historyList: HistoryNode[] = [ + { + userId: -1, + userAvatars: [], + userName: 'Lone Iversen', + timestamp: 'December 5, 2022 2:59 PM', + comment: undefined, + entityType: 'Document', + logType: 'Save', + nodeId: '1058', + parameters: undefined, + }, + { + userId: -1, + userAvatars: [], + userName: 'Lone Iversen', + timestamp: 'December 5, 2022 2:59 PM', + comment: undefined, + entityType: 'Document', + logType: 'Unpublish', + nodeId: '1058', + parameters: undefined, + }, + { + userId: -1, + userAvatars: [], + userName: 'Lone Iversen', + timestamp: 'December 5, 2022 2:59 PM', + comment: undefined, + entityType: 'Document', + logType: 'Publish', + nodeId: '1058', + parameters: undefined, + }, + + { + userId: -1, + userAvatars: [], + userName: 'Lone Iversen', + timestamp: 'December 5, 2022 2:59 PM', + comment: undefined, + entityType: 'Document', + logType: 'Save', + nodeId: '1058', + parameters: undefined, + }, + + { + userId: -1, + userAvatars: [], + userName: 'Lone Iversen', + timestamp: 'December 5, 2022 2:59 PM', + comment: undefined, + entityType: 'Document', + logType: 'Save', + nodeId: '1058', + parameters: undefined, + }, + ]; + + @state() + private _total?: number; + + @state() + private _currentPage = 1; + @state() private _nodeName = ''; private _workspaceContext?: UmbWorkspaceEntityContextInterface; + private itemsPerPage = 10; constructor() { super(); @@ -36,6 +201,7 @@ export class UmbWorkspaceViewContentInfoElement extends UmbLitElement { if (!this._workspaceContext) return; this._nodeName = 'TBD, with variants this is not as simple.'; + /* this.observe(this._workspaceContext.name, (name) => { this._nodeName = name || ''; @@ -43,8 +209,123 @@ export class UmbWorkspaceViewContentInfoElement extends UmbLitElement { */ } + #onPageChange(event: UUIPaginationEvent) { + if (this._currentPage === event.target.current) return; + this._currentPage = event.target.current; + //TODO: Run endpoint to get next history parts + } + render() { - return html`
Info Workspace View for ${this._nodeName}
`; + return html`
+ ${this.#renderLinksSection()} + + + ${repeat( + this._historyList, + (item) => item.timestamp, + (item) => this.#renderHistory(item) + )} + + ${this.#renderHistoryPagination()} + +
+
+ ${this.#renderGeneralSection()} +
`; + } + + #renderLinksSection() { + //repeat + return html``; + } + + #renderGeneralSection() { + return html` +
+ Status + Published +
+
+ Created Date + ... +
+
+ Document Type + document type picker? +
+
+ Template + template picker? +
+
+ Id + ... +
+ `; + } + + #renderHistory(history: HistoryNode) { + return html` + ${this.#renderTag(history.logType)} ${this.#renderTagDescription(history.logType)} + + Rollback + + `; + } + + #renderHistoryPagination() { + if (!this._total) return nothing; + + const totalPages = Math.ceil(this._total / this.itemsPerPage); + + if (totalPages <= 1) return nothing; + + return html``; + } + + #renderTag(type?: HistoryLogType) { + switch (type) { + case 'Publish': + return html`Publish`; + case 'Unpublish': + return html`Unpublish`; + case 'Save': + return html`Save`; + case 'ContentVersionEnableCleanup': + return html`Save`; + case 'ContentVersionPreventCleanup': + return html`Save`; + default: + return 'Could not detech log type'; + } + } + + #renderTagDescription(type?: HistoryLogType, params?: string) { + switch (type) { + case 'Publish': + return html`Content published`; + case 'Unpublish': + return html`Content unpublished`; + case 'Save': + return html`Content saved`; + case 'ContentVersionEnableCleanup': + return html`Cleanup enabled for version: ${params}`; + case 'ContentVersionPreventCleanup': + return html`Cleanup disabled for version: ${params}`; + default: + return 'Could not detech log type'; + } } }