move current user modal

This commit is contained in:
Mads Rasmussen
2023-03-08 11:08:49 +01:00
parent 3d3bfa1e16
commit f5329e010d
7 changed files with 42 additions and 18 deletions

View File

@@ -1,209 +0,0 @@
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, CSSResultGroup, html, nothing } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { UmbModalHandler, UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '..';
import {
UmbCurrentUserHistoryStore,
UmbCurrentUserHistoryItem,
UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN,
} from '../../../src/backoffice/users/current-user/current-user-history.store';
import {
UmbCurrentUserStore,
UMB_CURRENT_USER_STORE_CONTEXT_TOKEN,
} from '../../../src/backoffice/users/current-user/current-user.store';
import type { UserDetails } from '@umbraco-cms/models';
import { UmbLitElement } from '@umbraco-cms/element';
@customElement('umb-modal-layout-current-user')
export class UmbModalLayoutCurrentUserElement extends UmbLitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
:host {
display: block;
color: var(--uui-color-text);
}
:host,
umb-workspace-layout {
width: 100%;
height: 100%;
}
#main {
padding: var(--uui-size-space-5);
display: flex;
flex-direction: column;
gap: var(--uui-size-space-3);
}
#umbraco-id-buttons {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-3);
}
#recent-history {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-3);
}
#recent-history-items {
display: flex;
flex-direction: column;
gap: var(--uui-size-space-4);
}
.history-item {
display: grid;
grid-template-columns: 32px 1fr;
grid-template-rows: 1fr;
color: var(--uui-color-interactive);
text-decoration: none;
}
.history-item uui-icon {
margin-top: var(--uui-size-space-1);
}
.history-item:hover {
color: var(--uui-color-interactive-emphasis);
}
.history-item > div {
color: inherit;
text-decoration: none;
display: flex;
flex-direction: column;
line-height: 1.4em;
}
.history-item > div > span {
font-size: var(--uui-size-4);
opacity: 0.5;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
`,
];
@property({ attribute: false })
modalHandler?: UmbModalHandler;
@state()
private _currentUser?: UserDetails;
@state()
private _history: Array<UmbCurrentUserHistoryItem> = [];
private _modalContext?: UmbModalContext;
private _currentUserStore?: UmbCurrentUserStore;
private _currentUserHistoryStore?: UmbCurrentUserHistoryStore;
constructor() {
super();
this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => {
this._modalContext = instance;
});
this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => {
this._currentUserStore = instance;
this._observeCurrentUser();
});
this.consumeContext(UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, (instance) => {
this._currentUserHistoryStore = instance;
this._observeHistory();
});
this._observeCurrentUser();
}
private async _observeCurrentUser() {
if (!this._currentUserStore) return;
this.observe(this._currentUserStore.currentUser, (currentUser) => {
this._currentUser = currentUser;
});
}
private async _observeHistory() {
if (this._currentUserHistoryStore) {
this.observe(this._currentUserHistoryStore.latestHistory, (history) => {
this._history = history;
});
}
}
private _close() {
this.modalHandler?.close();
}
private _edit() {
if (!this._currentUser) return;
history.pushState(null, '', '/section/users/view/users/user/' + this._currentUser.key); //TODO Change to a tag with href and make dynamic
this._close();
}
private _changePassword() {
if (!this._modalContext) return;
this._modalContext.changePassword({ requireOldPassword: this._currentUserStore?.isAdmin || false });
}
private _renderHistoryItem(item: UmbCurrentUserHistoryItem) {
return html`
<a href=${item.path} class="history-item">
<uui-icon name="umb:link"></uui-icon>
<div>
<b>${Array.isArray(item.label) ? item.label[0] : item.label}</b>
<span>
${Array.isArray(item.label)
? item.label.map((label, index) => {
if (index === 0) return;
return html`
<span>${label}</span>
${index !== item.label.length - 1 ? html`<span>${'>'}</span>` : nothing}
`;
})
: nothing}
</span>
</div>
</a>
`;
}
private _logout() {
this._currentUserStore?.logout();
}
render() {
return html`
<umb-workspace-layout headline="${this._currentUser?.name || ''}">
<div id="main">
<uui-box>
<b slot="headline">Your profile</b>
<uui-button look="primary" @click=${this._edit}>Edit</uui-button>
<uui-button look="primary" @click=${this._changePassword}>Change password</uui-button>
</uui-box>
<uui-box>
<b slot="headline">External login providers</b>
<umb-extension-slot id="externalLoginProviders" type="externalLoginProvider"></umb-extension-slot>
</uui-box>
<div>
<umb-extension-slot id="userDashboards" type="userDashboard"></umb-extension-slot>
</div>
<uui-box>
<b slot="headline">Recent History</b>
<div id="recent-history-items">
${this._history.reverse().map((item) => html` ${this._renderHistoryItem(item)} `)}
</div>
</uui-box>
</div>
<div slot="actions">
<uui-button @click=${this._close} look="secondary">Close</uui-button>
<uui-button @click=${this._logout} look="primary" color="danger">Logout</uui-button>
</div>
</umb-workspace-layout>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-modal-layout-current-user': UmbModalLayoutCurrentUserElement;
}
}

View File

@@ -28,7 +28,7 @@ export class UmbModalHandler {
constructor(
host: UmbControllerHostInterface,
modalAlias: string | UmbModalToken,
data: unknown,
data?: unknown,
config?: UmbModalConfig
) {
this.#host = host;
@@ -68,10 +68,15 @@ export class UmbModalHandler {
return modalDialogElement;
}
async #createLayoutElement(manifest: ManifestModal, data: unknown) {
async #createLayoutElement(manifest: ManifestModal, data?: unknown) {
// TODO: add fallback element if no layout is found
const layoutElement = (await createExtensionElement(manifest)) as any;
layoutElement.data = data;
layoutElement.modalHandler = this;
if (layoutElement) {
layoutElement.data = data;
layoutElement.modalHandler = this;
}
return layoutElement;
}
@@ -88,7 +93,7 @@ export class UmbModalHandler {
It makes this code a bit more complex. The main idea is to have the element as part of the modalHandler so it is possible to dispatch events from within the modal element to the one that opened it.
Now when the element is an observable it makes it more complex because this host needs to subscribe to updates to the element, instead of just having a reference to it.
If we find a better generic solution to communicate between the modal and the host, then we can remove the element as part of the modalHandler. */
#observeModal(modalAlias: string, data: unknown) {
#observeModal(modalAlias: string, data?: unknown) {
new UmbObserverController(
this.#host,
umbExtensionsRegistry.getByTypeAndAlias('modal', modalAlias),

View File

@@ -3,7 +3,7 @@ import './layouts/confirm/modal-layout-confirm.element';
import '../../src/backoffice/documents/documents/modals/document-picker/document-picker-modal.element';
import './layouts/media-picker/modal-layout-media-picker.element';
import './layouts/property-editor-ui-picker/modal-layout-property-editor-ui-picker.element';
import './layouts/modal-layout-current-user.element';
import '../../src/backoffice/users/current-user/modals/current-user/current-user-modal.element';
import './layouts/icon-picker/modal-layout-icon-picker.element';
import '../../src/backoffice/settings/languages/language-picker/language-picker-modal-layout.element';
import './layouts/link-picker/modal-layout-link-picker.element';
@@ -204,7 +204,7 @@ export class UmbModalContext {
* @return {*} {UmbModalHandler}
* @memberof UmbModalContext
*/
public open<T = unknown>(modalAlias: string | UmbModalToken<T>, data: T, config?: UmbModalConfig): UmbModalHandler {
public open<T = unknown>(modalAlias: string | UmbModalToken<T>, data?: T, config?: UmbModalConfig): UmbModalHandler {
const modalHandler = new UmbModalHandler(this.host, modalAlias, data, config);
modalHandler.containerElement.addEventListener('close-end', () => this.#onCloseEnd(modalHandler));