workspace info (#546)

* info workspace w history

* split history ui into list and nodes

* line between histories

* same folder

* rollback button

* round button

* history logtype

* longer list for mock

* storybook & other sections of workspace info

* rename elements

---------

Co-authored-by: Lone Iversen <108085781+loivsen@users.noreply.github.com>
Co-authored-by: Mads Rasmussen <madsr@hey.com>
This commit is contained in:
Niels Lyngsø
2023-03-09 10:47:57 +01:00
committed by GitHub
parent 319d7a7c99
commit b4225c11d3
5 changed files with 471 additions and 3 deletions

View File

@@ -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`<div id="wrapper">
<div class="user-info">
<uui-avatar .name="${this.name ?? 'Unknown'}" ?src="${this.src}"></uui-avatar>
<div>
<span class="name">${this.name}</span>
<span class="detail">${this.detail}</span>
</div>
</div>
<div class="slots-wrapper">
<slot id="description"></slot>
<slot id="actions-container" name="actions"></slot>
</div>
</div>`;
}
}
export default UmbHistoryItemElement;
declare global {
interface HTMLElementTagNameMap {
'umb-history-item': UmbHistoryItemElement;
}
}

View File

@@ -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`<div>
<slot></slot>
</div>`;
}
}
export default UmbHistoryListElement;
declare global {
interface HTMLElementTagNameMap {
'umb-history-list': UmbHistoryListElement;
}
}

View File

@@ -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<UmbHistoryListElement> = () => html` <umb-history-list>
<umb-history-item name="Name attribute" detail="Detail attribute">
Default slot
<uui-button slot="actions" label="action">Action slot</uui-button>
</umb-history-item>
<umb-history-item name="Name attribute" detail="Detail attribute">
Default slot
<uui-button slot="actions" label="action">Action slot</uui-button>
</umb-history-item>
<umb-history-item name="Name attribute" detail="Detail attribute">
Default slot
<uui-button slot="actions" label="action">Action slot</uui-button>
</umb-history-item>
</umb-history-list>`;
AAAOverview.storyName = 'Overview';
export const Node: Story<UmbHistoryItemElement> = () => html`<umb-history-item
name="Name attribute"
detail="Detail attribute">
Default slot
<uui-button slot="actions" label="action">Action slot</uui-button>
</umb-history-item>`;

View File

@@ -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';

View File

@@ -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<DocumentModel>;
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`<div>Info Workspace View for ${this._nodeName}</div>`;
return html`<div class="container">
<uui-box headline="Links" style="--uui-box-default-padding: 0;"> ${this.#renderLinksSection()} </uui-box>
<uui-box headline="History">
<umb-history-list>
${repeat(
this._historyList,
(item) => item.timestamp,
(item) => this.#renderHistory(item)
)}
</umb-history-list>
${this.#renderHistoryPagination()}
</uui-box>
</div>
<div class="container">
<uui-box headline="General" id="general-section">${this.#renderGeneralSection()}</uui-box>
</div>`;
}
#renderLinksSection() {
//repeat
return html`<div id="link-section">
<a href="http://google.com" target="_blank" class="link-item with-href">
<span class="link-language">da-DK</span>
<span class="link-content"> <uui-icon name="umb:out"></uui-icon>google.com </span>
</a>
<div class="link-item">
<span class="link-language">en-EN</span>
<span class="link-content italic"> This document is published but is not in the cache</span>
</div>
</div>`;
}
#renderGeneralSection() {
return html`
<div class="general-item">
<strong>Status</strong>
<span><uui-tag color="positive" look="primary" label="Published">Published</uui-tag></span>
</div>
<div class="general-item">
<strong>Created Date</strong>
<span>...</span>
</div>
<div class="general-item">
<strong>Document Type</strong>
<span>document type picker?</span>
</div>
<div class="general-item">
<strong>Template</strong>
<span>template picker?</span>
</div>
<div class="general-item">
<strong>Id</strong>
<span>...</span>
</div>
`;
}
#renderHistory(history: HistoryNode) {
return html` <umb-history-item .name="${history.userName}" .detail="${history.timestamp}">
<span class="log-type">${this.#renderTag(history.logType)} ${this.#renderTagDescription(history.logType)}</span>
<uui-button label="Rollback" look="secondary" slot="actions">
<uui-icon name="umb:undo"></uui-icon> Rollback
</uui-button>
</umb-history-item>`;
}
#renderHistoryPagination() {
if (!this._total) return nothing;
const totalPages = Math.ceil(this._total / this.itemsPerPage);
if (totalPages <= 1) return nothing;
return html`<div class="pagination">
<uui-pagination .total=${totalPages} @change="${this.#onPageChange}"></uui-pagination>
</div>`;
}
#renderTag(type?: HistoryLogType) {
switch (type) {
case 'Publish':
return html`<uui-tag look="primary" color="positive" label="Publish">Publish</uui-tag>`;
case 'Unpublish':
return html`<uui-tag look="primary" color="warning" label="Unpublish">Unpublish</uui-tag>`;
case 'Save':
return html`<uui-tag look="primary" label="Save">Save</uui-tag>`;
case 'ContentVersionEnableCleanup':
return html`<uui-tag look="secondary" label="Content Version Enable Cleanup">Save</uui-tag>`;
case 'ContentVersionPreventCleanup':
return html`<uui-tag look="secondary" label="Content Version Prevent Cleanup">Save</uui-tag>`;
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';
}
}
}