Merge branch 'main' into v14/chore/bundling-language-package

This commit is contained in:
Mads Rasmussen
2024-06-17 13:08:43 +02:00
committed by GitHub
7 changed files with 141 additions and 44 deletions

View File

@@ -46,7 +46,7 @@ export default {
logout: 'Exit',
move: 'Move to',
notify: 'Notifications',
protect: 'Restrict Public Access',
protect: 'Public Access',
publish: 'Publish',
refreshNode: 'Reload',
remove: 'Remove',

View File

@@ -45,7 +45,7 @@ export default {
logout: 'Exit',
move: 'Move to',
notify: 'Notifications',
protect: 'Restrict Public Access',
protect: 'Public Access',
publish: 'Publish',
refreshNode: 'Reload',
remove: 'Remove',

View File

@@ -25,6 +25,10 @@ const entityActions: Array<ManifestTypes> = [
{
alias: UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS,
},
{
alias: 'Umb.Condition.SectionUserPermission',
match: 'Umb.Section.Members',
},
],
},
];

View File

@@ -1,12 +1,12 @@
import { UmbDocumentPublicAccessRepository } from '../repository/public-access.repository.js';
import { UmbDocumentDetailRepository } from '../../../repository/index.js';
import { UmbDocumentItemRepository } from '../../../repository/index.js';
import type { UmbInputDocumentElement } from '../../../components/index.js';
import type { UmbPublicAccessModalData, UmbPublicAccessModalValue } from './public-access-modal.token.js';
import { css, customElement, html, nothing, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbInputMemberElement } from '@umbraco-cms/backoffice/member';
import type { UmbInputMemberGroupElement } from '@umbraco-cms/backoffice/member-group';
import { UmbMemberDetailRepository, type UmbInputMemberElement } from '@umbraco-cms/backoffice/member';
import { UmbMemberGroupItemRepository, type UmbInputMemberGroupElement } from '@umbraco-cms/backoffice/member-group';
import type { PublicAccessRequestModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UUIRadioEvent } from '@umbraco-cms/backoffice/external/uui';
@@ -32,56 +32,52 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
private _selection: Array<string> = [];
@state()
private _loginPageId?: string;
private _loginDocumentId?: string;
@state()
private _errorPageId?: string;
private _errorDocumentId?: string;
// Init
firstUpdated() {
this.#unique = this.data?.unique;
this.#getDocumentName();
this.#getPublicAccessModel();
}
async #getDocumentName() {
if (!this.#unique) return;
// Should this be done here or in the action file?
const { data } = await new UmbDocumentDetailRepository(this).requestByUnique(this.#unique);
const { data } = await new UmbDocumentItemRepository(this).requestItems([this.#unique]);
if (!data) return;
const item = data[0];
//TODO How do we ensure we get the correct variant?
this._documentName = data.variants[0]?.name;
this._documentName = item.variants[0]?.name;
if (item.isProtected) {
this.#getPublicAccessModel();
}
}
async #getPublicAccessModel() {
if (!this.#unique) return;
//const { data } = (await this.#publicAccessRepository.read(this.#unique));
// TODO Currently returning "void". Remove mock data when API is ready. Will it be Response or Request model?
const data: any = undefined;
/*const data: PublicAccessResponseModel = {
members: [{ name: 'Agent', id: '007' }],
groups: [],
loginPageId: '123',
errorPageId: '456',
};*/
const { data } = await this.#publicAccessRepository.read(this.#unique);
if (!data) return;
this.#isNew = false;
this._startPage = false;
// Specific or Groups
this._specific = data.members.length > 0 ? true : false;
this._specific = data.members.length > 0;
//selection
if (data.members.length > 0) {
this._selection = data.members.map((m: any) => m.id);
this._selection = data.members.map((m) => m.id);
} else if (data.groups.length > 0) {
this._selection = data.groups.map((g: any) => g.id);
this._selection = data.groups.map((g) => g.id);
}
this._loginPageId = data.loginPageId;
this._errorPageId = data.errorPageId;
this._loginDocumentId = data.loginDocument.id;
this._errorDocumentId = data.errorDocument.id;
}
// Modal events
@@ -91,30 +87,54 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
}
async #handleSave() {
if (!this._loginPageId || !this._errorPageId || !this.#unique) return;
const groups = this._specific ? [] : this._selection;
const members = this._specific ? this._selection : [];
if (!this._loginDocumentId || !this._errorDocumentId || !this.#unique) return;
// TODO: [v15] Currently the Management API doesn't support passing the member/group ids, only the userNames/names.
// This is a temporary solution where we have to look them up until the API is updated to support this.
const requestBody: PublicAccessRequestModel = {
memberGroupNames: groups,
memberUserNames: members,
loginDocument: { id: this._loginPageId },
errorDocument: { id: this._errorPageId },
memberGroupNames: [],
memberUserNames: [],
loginDocument: { id: this._loginDocumentId },
errorDocument: { id: this._errorDocumentId },
};
if (this.#isNew) {
this.#publicAccessRepository.create(this.#unique, requestBody);
if (this._specific) {
// Members
// user name is not part of the item model, so we need to look it up from the member detail repository
// be aware that the detail repository requires access to the member section.
const repo = new UmbMemberDetailRepository(this);
const promises = this._selection.map((memberId) => repo.requestByUnique(memberId));
const responses = await Promise.all(promises);
const memberUserNames = responses
.filter((response) => response.data)
.map((response) => response.data?.username) as string[];
requestBody.memberUserNames = memberUserNames;
} else {
this.#publicAccessRepository.update(this.#unique, requestBody);
// Groups
const repo = new UmbMemberGroupItemRepository(this);
const { data } = await repo.requestItems(this._selection);
if (!data) throw new Error('No Member groups returned');
const groupNames = data
.filter((groupItem) => this._selection.includes(groupItem.unique))
.map((groupItem) => groupItem.name);
requestBody.memberGroupNames = groupNames;
}
if (this.#isNew) {
await this.#publicAccessRepository.create(this.#unique, requestBody);
} else {
await this.#publicAccessRepository.update(this.#unique, requestBody);
}
this.modalContext?.submit();
}
#handleDelete() {
async #handleDelete() {
if (!this.#unique) return;
this.#publicAccessRepository.delete(this.#unique);
await this.#publicAccessRepository.delete(this.#unique);
this.modalContext?.submit();
}
@@ -125,11 +145,11 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
// Change Events
#onChangeLoginPage(e: CustomEvent) {
this._loginPageId = (e.target as UmbInputDocumentElement).selection[0];
this._loginDocumentId = (e.target as UmbInputDocumentElement).selection[0];
}
#onChangeErrorPage(e: CustomEvent) {
this._errorPageId = (e.target as UmbInputDocumentElement).selection[0];
this._errorDocumentId = (e.target as UmbInputDocumentElement).selection[0];
}
#onChangeGroup(e: CustomEvent) {
@@ -182,7 +202,10 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
<small>
<umb-localize key="publicAccess_paLoginPageHelp"> Choose the page that contains the login form </umb-localize>
</small>
<umb-input-document max="1" @change=${this.#onChangeLoginPage}></umb-input-document>
<umb-input-document
.value=${this._loginDocumentId ? this._loginDocumentId : ''}
max="1"
@change=${this.#onChangeLoginPage}></umb-input-document>
</div>
<br />
<div class="select-item">
@@ -192,7 +215,10 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
Used when people are logged on, but do not have access
</umb-localize>
</small>
<umb-input-document max="1" @change=${this.#onChangeErrorPage}></umb-input-document>
<umb-input-document
.value=${this._errorDocumentId ? this._errorDocumentId : ''}
max="1"
@change=${this.#onChangeErrorPage}></umb-input-document>
</div>`;
}
@@ -220,7 +246,7 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
look="primary"
color="positive"
label=${this.localize.term('buttons_save')}
?disabled=${!this._loginPageId || !this._errorPageId || this._selection.length === 0}
?disabled=${!this._loginDocumentId || !this._errorDocumentId || this._selection.length === 0}
@click="${this.#handleSave}"></uui-button>`
: html`<uui-button
slot="actions"

View File

@@ -1,8 +1,13 @@
import { UMB_PUBLIC_ACCESS_MODAL } from './modal/public-access-modal.token.js';
import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action';
import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action';
import {
UmbEntityActionBase,
UmbRequestReloadChildrenOfEntityEvent,
UmbRequestReloadStructureForEntityEvent,
} from '@umbraco-cms/backoffice/entity-action';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { UmbDocumentDetailRepository } from '@umbraco-cms/backoffice/document';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
export class UmbDocumentPublicAccessEntityAction extends UmbEntityActionBase<never> {
constructor(host: UmbDocumentDetailRepository, args: UmbEntityActionArgs<never>) {
@@ -14,5 +19,23 @@ export class UmbDocumentPublicAccessEntityAction extends UmbEntityActionBase<nev
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
const modal = modalManager.open(this, UMB_PUBLIC_ACCESS_MODAL, { data: { unique: this.args.unique } });
await modal.onSubmit();
this.#requestReloadEntity();
}
async #requestReloadEntity() {
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
const entityStructureEvent = new UmbRequestReloadStructureForEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
});
const entityChildrenEvent = new UmbRequestReloadChildrenOfEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
});
actionEventContext.dispatchEvent(entityStructureEvent);
actionEventContext.dispatchEvent(entityChildrenEvent);
}
}

View File

@@ -25,7 +25,7 @@ export class UmbDocumentPublicAccessRepository extends UmbControllerBase impleme
if (!unique) throw new Error('unique is missing');
if (!data) throw new Error('Data is missing');
const { error } = await this.#dataSource.update(unique, data);
const { error } = await this.#dataSource.create(unique, data);
if (!error) {
const notification = { data: { message: `Public acccess setting created` } };
this.#notificationContext?.peek('positive', notification);

View File

@@ -74,6 +74,7 @@ export class UmbDocumentTreeItemElement extends UmbTreeItemElementBase<UmbDocume
${this.item?.documentType.icon
? html`
<umb-icon id="icon" slot="icon" name="${this.item.documentType.icon}"></umb-icon>
${this.item.isProtected ? this.#renderIsProtectedIcon() : nothing}
<!--
// TODO: implement correct status symbol
<span id="status-symbol"></span>
@@ -90,6 +91,10 @@ export class UmbDocumentTreeItemElement extends UmbTreeItemElementBase<UmbDocume
> `;
}
#renderIsProtectedIcon() {
return html`<umb-icon id="icon-lock" slot="icon" name="icon-lock" title="Protected"></umb-icon>`;
}
static styles = [
UmbTextStyles,
css`
@@ -113,6 +118,45 @@ export class UmbDocumentTreeItemElement extends UmbTreeItemElementBase<UmbDocume
border-radius: 100%;
}
#icon-lock {
position: absolute;
bottom: -5px;
right: -5px;
font-size: 10px;
background: var(--uui-color-surface);
width: 14px;
height: 14px;
border-radius: 100%;
line-height: 14px;
}
:hover #icon-lock {
background: var(--uui-color-surface-emphasis);
}
/** Active */
[active] #icon-lock {
background: var(--uui-color-current);
}
[active]:hover #icon-lock {
background: var(--uui-color-current-emphasis);
}
/** Selected */
[selected] #icon-lock {
background-color: var(--uui-color-selected);
}
[selected]:hover #icon-lock {
background-color: var(--uui-color-selected-emphasis);
}
/** Disabled */
[disabled] #icon-lock {
background-color: var(--uui-color-disabled);
}
.draft {
opacity: 0.6;
}