Merge pull request #2410 from umbraco/v15/feature/select-all-option-in-publishing-dialogs
Feature: Select all variants option in publishing dialogs
This commit is contained in:
@@ -318,6 +318,7 @@ export default {
|
||||
createEmpty: 'Napravi novi',
|
||||
createFromClipboard: 'Zalijepi iz međuspremnika',
|
||||
nodeIsInTrash: 'Ova stavka je u korpi za otpatke',
|
||||
saveModalTitle: 'Spremi',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Kreirajte novi predložak sadržaja iz <em>%0%</em>',
|
||||
|
||||
@@ -300,6 +300,7 @@ export default {
|
||||
createEmpty: 'Create new',
|
||||
createFromClipboard: 'Paste from clipboard',
|
||||
nodeIsInTrash: 'This item is in the Recycle Bin',
|
||||
saveModalTitle: 'Uložit',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Vytvořit novou šablonu obsahu z <em>%0%</em>',
|
||||
|
||||
@@ -331,6 +331,7 @@ export default {
|
||||
variantSendForApprovalNotAllowed: 'Ni chaniateir anfon am gymeradwyaeth',
|
||||
variantScheduleNotAllowed: 'Ni chaniateir amserlennu',
|
||||
variantUnpublishNotAllowed: 'Ni chaniateir dad-gyhoeddi',
|
||||
saveModalTitle: 'Achub',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: "Creu Templed Cynnwys newydd o '%0%'",
|
||||
|
||||
@@ -326,6 +326,7 @@ export default {
|
||||
variantSendForApprovalNotAllowed: 'Send for approval is not allowed',
|
||||
variantScheduleNotAllowed: 'Schedule is not allowed',
|
||||
variantUnpublishNotAllowed: 'Unpublish is not allowed',
|
||||
saveModalTitle: 'Gem',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: "Opret en ny indholdsskabelon fra '%0%'",
|
||||
|
||||
@@ -332,6 +332,7 @@ export default {
|
||||
variantSendForApprovalNotAllowed: 'Zur Genehmigung senden ist nicht erlaubt.',
|
||||
variantScheduleNotAllowed: 'Plannung ist nicht erlaubt',
|
||||
variantUnpublishNotAllowed: 'Veröffentlichung zurücknehmen ist nicht erlaubt.',
|
||||
saveModalTitle: 'Speichern',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Erzeuge eine neue Inhaltsvorlage von <em>%0%</em>',
|
||||
|
||||
@@ -345,6 +345,7 @@ export default {
|
||||
variantScheduleNotAllowed: 'Schedule is not allowed',
|
||||
variantUnpublishNotAllowed: 'Unpublish is not allowed',
|
||||
selectAllVariants: 'Select all variants',
|
||||
saveModalTitle: 'Save',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: "Create a new Document Blueprint from '%0%'",
|
||||
@@ -930,6 +931,7 @@ export default {
|
||||
header: 'Header',
|
||||
systemField: 'system field',
|
||||
lastUpdated: 'Last Updated',
|
||||
selectAll: 'Select all',
|
||||
skipToMenu: 'Skip to menu',
|
||||
skipToContent: 'Skip to content',
|
||||
restore: 'Restore',
|
||||
|
||||
@@ -341,6 +341,7 @@ export default {
|
||||
variantScheduleNotAllowed: 'Schedule is not allowed',
|
||||
variantUnpublishNotAllowed: 'Unpublish is not allowed',
|
||||
selectAllVariants: 'Select all variants',
|
||||
saveModalTitle: 'Save',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: "Create a new Document Blueprint from '%0%'",
|
||||
@@ -953,6 +954,7 @@ export default {
|
||||
addChild: 'Add child',
|
||||
editDataType: 'Edit data type',
|
||||
navigateSections: 'Navigate sections',
|
||||
selectAll: 'Select all',
|
||||
shortcut: 'Shortcuts',
|
||||
showShortcuts: 'show shortcuts',
|
||||
toggleListView: 'Toggle list view',
|
||||
|
||||
@@ -202,6 +202,7 @@ export default {
|
||||
addTextBox: 'Añadir otra caja de texto',
|
||||
removeTextBox: 'Eliminar caja de texto',
|
||||
contentRoot: 'Raíz de contenido',
|
||||
saveModalTitle: 'Guardar',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Crear nueva Plantilla de Contenido desde <em>%0%</em>',
|
||||
|
||||
@@ -297,6 +297,7 @@ export default {
|
||||
schedulePublishHelp: "Sélectionnez la date et l'heure de publication/dépublication de l'élément de contenu.",
|
||||
createEmpty: 'Créer nouveau',
|
||||
createFromClipboard: 'Copier du clipboard',
|
||||
saveModalTitle: 'Sauver',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Créer un nouveau Modèle de Contenu à partir de <em>%0%</em>',
|
||||
|
||||
@@ -113,6 +113,7 @@ export default {
|
||||
updateDate: 'נערך לאחרונה',
|
||||
uploadClear: 'הסר קובץ',
|
||||
urls: 'קשר למסמך',
|
||||
saveModalTitle: 'שמור',
|
||||
},
|
||||
create: {
|
||||
chooseNode: 'היכן ברצונך ליצור את %0%',
|
||||
|
||||
@@ -319,6 +319,7 @@ export default {
|
||||
createEmpty: 'Kreiraj novo',
|
||||
createFromClipboard: 'Zalijepi iz međuspremnika',
|
||||
nodeIsInTrash: 'Ova stavka je u košu za smeće',
|
||||
saveModalTitle: 'Spremi',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Kreirajte novi predložak sadržaja iz <em>%0%</em>',
|
||||
|
||||
@@ -331,6 +331,7 @@ export default {
|
||||
createEmpty: 'Crea nuovo/a',
|
||||
createFromClipboard: 'Incolla dagli appunti',
|
||||
nodeIsInTrash: 'Questo articolo è nel cestino',
|
||||
saveModalTitle: 'Salva',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: "Crea un nuovo modello di contenuto da '%0%'",
|
||||
|
||||
@@ -148,6 +148,7 @@ export default {
|
||||
notmemberof: 'グループのメンバーではありません',
|
||||
childItems: '子コンテンツ',
|
||||
target: 'ターゲット',
|
||||
saveModalTitle: '保存',
|
||||
},
|
||||
media: {
|
||||
clickToUpload: 'クリックしてアップロードする',
|
||||
|
||||
@@ -113,6 +113,7 @@ export default {
|
||||
updateDate: '마지막 수정일',
|
||||
uploadClear: '파일 삭제',
|
||||
urls: '문서에 링크',
|
||||
saveModalTitle: '저장',
|
||||
},
|
||||
create: {
|
||||
chooseNode: '새로운 %0% (을)를 생성할 위치를 지정하십시오',
|
||||
|
||||
@@ -146,6 +146,7 @@ export default {
|
||||
notmemberof: 'Ikke medlem av gruppe(ne)',
|
||||
childItems: 'Undersider',
|
||||
target: 'Åpne i vindu',
|
||||
saveModalTitle: 'Lagre',
|
||||
},
|
||||
media: {
|
||||
clickToUpload: 'Klikk for å laste opp',
|
||||
|
||||
@@ -317,6 +317,7 @@ export default {
|
||||
createEmpty: 'Maak nieuw',
|
||||
createFromClipboard: 'Plakken vanaf het klembord',
|
||||
nodeIsInTrash: 'Dit item is in de prullenbak',
|
||||
saveModalTitle: 'Opslaan',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Nieuw Inhoudssjabloon aanmaken voor <em>%0%</em>',
|
||||
|
||||
@@ -199,6 +199,7 @@ export default {
|
||||
addTextBox: 'Dodaj kolejne pole tekstowe',
|
||||
removeTextBox: 'Usuń te pole tekstowe',
|
||||
contentRoot: 'Korzeń zawartości',
|
||||
saveModalTitle: 'Zapisz',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: 'Stwórz nowy Szablon Zawartości z <em>%0%</em>',
|
||||
|
||||
@@ -113,6 +113,7 @@ export default {
|
||||
updateDate: 'Última edição',
|
||||
uploadClear: 'Remover arquivo',
|
||||
urls: 'Link ao documento',
|
||||
saveModalTitle: 'Salvar',
|
||||
},
|
||||
create: {
|
||||
chooseNode: 'Onde você quer criar seu novo(a) %0%',
|
||||
|
||||
@@ -250,6 +250,7 @@ export default {
|
||||
urls: 'Ссылка на документ',
|
||||
addTextBox: 'Добавить новое поле текста',
|
||||
removeTextBox: 'Удалить это поле текста',
|
||||
saveModalTitle: 'Сохранить',
|
||||
},
|
||||
contentPicker: {
|
||||
pickedTrashedItem: 'Выбран элемент содержимого, который в настоящее время удален или находится в корзине',
|
||||
|
||||
@@ -233,6 +233,7 @@ export default {
|
||||
listViewNoContent: 'Inga undernoder har lagts till',
|
||||
noChanges: 'Inga ändringar har gjorts',
|
||||
notCreated: 'Ej skapad',
|
||||
saveModalTitle: 'Spara',
|
||||
},
|
||||
contentTypeEditor: {
|
||||
yesDelete: 'Ja, ta bort',
|
||||
|
||||
@@ -305,6 +305,7 @@ export default {
|
||||
createEmpty: 'Yeni oluştur',
|
||||
createFromClipboard: 'Panodan yapıştır',
|
||||
nodeIsInTrash: "Bu öğe Geri Dönüşüm Kutusu'nda",
|
||||
saveModalTitle: 'Kaydet',
|
||||
},
|
||||
blueprints: {
|
||||
createBlueprintFrom: '<em>%0%</em> den yeni bir İçerik Şablonu oluşturun',
|
||||
|
||||
@@ -250,6 +250,7 @@ export default {
|
||||
urls: 'Посилання на документ',
|
||||
addTextBox: 'Додати нове текстове поле',
|
||||
removeTextBox: 'Видалити це текстове поле',
|
||||
saveModalTitle: 'Зберегти',
|
||||
},
|
||||
contentPicker: {
|
||||
pickedTrashedItem: 'Вибрано елемент вмісту, який вилучено або знаходиться в корзині.',
|
||||
|
||||
@@ -154,6 +154,7 @@ export default {
|
||||
scheduledPublishServerTime: '这将转换到服务器上的以下时间:',
|
||||
scheduledPublishDocumentation:
|
||||
'<a href="https://docs.umbraco.com/umbraco-cms/fundamentals/data/scheduled-publishing#timezones" target="_blank" rel="noopener">这是什么意思?</a>',
|
||||
saveModalTitle: '保存',
|
||||
},
|
||||
media: {
|
||||
clickToUpload: '点击上传',
|
||||
|
||||
@@ -153,6 +153,7 @@ export default {
|
||||
scheduledPublishServerTime: '預計發表的時間(伺服器端)',
|
||||
scheduledPublishDocumentation:
|
||||
'<a href="https://docs.umbraco.com/umbraco-cms/fundamentals/data/scheduled-publishing#timezones" target="_blank" rel="noopener">這是什麼意思?</a>',
|
||||
saveModalTitle: '保存',
|
||||
},
|
||||
media: {
|
||||
clickToUpload: '點選以便上傳',
|
||||
|
||||
@@ -238,6 +238,12 @@ describe('UmbSelectionManager', () => {
|
||||
expect(manager.getSelection()).to.deep.equal(['1', '2']);
|
||||
});
|
||||
|
||||
it('cant do the selection if the selection contains an item that is not allowed', () => {
|
||||
manager.setAllowLimitation((item) => item !== '2');
|
||||
expect(() => manager.setSelection(['1', '2'])).to.throw();
|
||||
expect(manager.getSelection()).to.deep.equal([]);
|
||||
});
|
||||
|
||||
it('deselects multiple items', () => {
|
||||
manager.setSelection(['1', '2', '3']);
|
||||
manager.deselect('1');
|
||||
|
||||
@@ -60,6 +60,13 @@ export class UmbSelectionManager<ValueType extends string | null = string | null
|
||||
public setSelection(value: Array<ValueType>) {
|
||||
if (this.getSelectable() === false) return;
|
||||
if (value === undefined) throw new Error('Value cannot be undefined');
|
||||
|
||||
value.forEach((unique) => {
|
||||
if (this.#allow(unique) === false) {
|
||||
throw new Error(`${unique} is now allowed to be selected`);
|
||||
}
|
||||
});
|
||||
|
||||
const newSelection = this.getMultiple() ? value : value.slice(0, 1);
|
||||
this.#selection.setValue(newSelection);
|
||||
}
|
||||
@@ -161,4 +168,13 @@ export class UmbSelectionManager<ValueType extends string | null = string | null
|
||||
public setAllowLimitation(compareFn: (unique: ValueType) => boolean): void {
|
||||
this.#allow = compareFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the function that determines if an item is selectable or not.
|
||||
* @returns {*}
|
||||
* @memberof UmbSelectionManager
|
||||
*/
|
||||
public getAllowLimitation() {
|
||||
return this.#allow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class UmbDocumentSaveModalElement extends UmbModalBaseElement<
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`<umb-body-layout headline=${this.localize.term('content_readyToSave')}>
|
||||
return html`<umb-body-layout headline=${this.localize.term('content_saveModalTitle')}>
|
||||
<p id="subtitle">
|
||||
<umb-localize key="content_variantsToSave">Choose which variants to be saved.</umb-localize>
|
||||
</p>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import type { UmbInputDateElement } from '@umbraco-cms/backoffice/components';
|
||||
import type { UUIBooleanInputElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-document-schedule-modal')
|
||||
export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
@@ -20,6 +21,9 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
@state()
|
||||
_selection: UmbDocumentScheduleModalValue['selection'] = [];
|
||||
|
||||
@state()
|
||||
_isAllSelected?: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.observe(
|
||||
@@ -28,6 +32,7 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
this._selection = selection.map((unique) => {
|
||||
return { unique, schedule: {} };
|
||||
});
|
||||
this._isAllSelected = this.#isAllSelected();
|
||||
},
|
||||
'_selection',
|
||||
);
|
||||
@@ -78,6 +83,25 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
return this._selection.some((s) => s.unique === unique);
|
||||
}
|
||||
|
||||
#onSelectAllChange(event: Event) {
|
||||
const allUniques = this._options.map((o) => o.unique);
|
||||
const filter = this.#selectionManager.getAllowLimitation();
|
||||
const allowedUniques = allUniques.filter((unique) => filter(unique));
|
||||
|
||||
if ((event.target as UUIBooleanInputElement).checked) {
|
||||
this.#selectionManager.setSelection(allowedUniques);
|
||||
} else {
|
||||
this.#selectionManager.setSelection([]);
|
||||
}
|
||||
}
|
||||
|
||||
#isAllSelected() {
|
||||
const allUniques = this._options.map((o) => o.unique);
|
||||
const filter = this.#selectionManager.getAllowLimitation();
|
||||
const allowedUniques = allUniques.filter((unique) => filter(unique));
|
||||
return this._selection.length === allowedUniques.length;
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`<umb-body-layout headline=${this.localize.term('general_scheduledPublishing')}>
|
||||
<p id="subtitle">
|
||||
@@ -108,11 +132,18 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
}
|
||||
|
||||
#renderOptions() {
|
||||
return repeat(
|
||||
this._options,
|
||||
(option) => option.unique,
|
||||
(option) => this.#renderItem(option),
|
||||
);
|
||||
return html`
|
||||
<uui-checkbox
|
||||
@change=${this.#onSelectAllChange}
|
||||
label=${this.localize.term('general_selectAll')}
|
||||
.checked=${this._isAllSelected}></uui-checkbox>
|
||||
|
||||
${repeat(
|
||||
this._options,
|
||||
(option) => option.unique,
|
||||
(option) => this.#renderItem(option),
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItem(option: UmbDocumentVariantOptionModel) {
|
||||
@@ -210,6 +241,14 @@ export class UmbDocumentScheduleModalElement extends UmbModalBaseElement<
|
||||
.publish-date > uui-form-layout-item:first-child {
|
||||
border-right: 1px dashed var(--uui-color-border);
|
||||
}
|
||||
|
||||
uui-checkbox {
|
||||
margin-bottom: var(--uui-size-space-3);
|
||||
}
|
||||
|
||||
uui-menu-item {
|
||||
--uui-menu-item-flat-structure: 1;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UmbDocumentVariantState, type UmbDocumentVariantOptionModel } from '../../types.js';
|
||||
import type { UUIBooleanInputElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import {
|
||||
css,
|
||||
customElement,
|
||||
@@ -27,6 +28,7 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement {
|
||||
this.selectionManager.selection,
|
||||
(selection) => {
|
||||
this._selection = selection;
|
||||
this._isAllSelected = this.#isAllSelected();
|
||||
},
|
||||
'_selectionManager',
|
||||
);
|
||||
@@ -38,6 +40,9 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement {
|
||||
@state()
|
||||
_selection: Array<string> = [];
|
||||
|
||||
@state()
|
||||
_isAllSelected?: boolean;
|
||||
|
||||
/**
|
||||
* A filter function that determines if an item is pickableFilter or not.
|
||||
* @memberof UmbDocumentVariantLanguagePickerElement
|
||||
@@ -65,16 +70,43 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement {
|
||||
}
|
||||
}
|
||||
|
||||
#onSelectAllChange(event: Event) {
|
||||
const allUniques = this.variantLanguageOptions.map((o) => o.unique);
|
||||
const filter = this.selectionManager.getAllowLimitation();
|
||||
const allowedUniques = allUniques.filter((unique) => filter(unique));
|
||||
|
||||
if ((event.target as UUIBooleanInputElement).checked) {
|
||||
this.selectionManager.setSelection(allowedUniques);
|
||||
} else {
|
||||
this.selectionManager.setSelection([]);
|
||||
}
|
||||
}
|
||||
|
||||
#isAllSelected() {
|
||||
const allUniques = this.variantLanguageOptions.map((o) => o.unique);
|
||||
const filter = this.selectionManager.getAllowLimitation();
|
||||
const allowedUniques = allUniques.filter((unique) => filter(unique));
|
||||
return this._selection.length === allowedUniques.length;
|
||||
}
|
||||
|
||||
override render() {
|
||||
return this.variantLanguageOptions.length
|
||||
? repeat(
|
||||
this.variantLanguageOptions,
|
||||
(option) => option.unique,
|
||||
(option) => html` ${this.#renderItem(option)} `,
|
||||
)
|
||||
: html`<uui-box>
|
||||
<umb-localize key="content_noVariantsToProcess">There are no available variants</umb-localize>
|
||||
</uui-box>`;
|
||||
if (this.variantLanguageOptions.length === 0) {
|
||||
return html`<uui-box>
|
||||
<umb-localize key="content_noVariantsToProcess">There are no available variants</umb-localize>
|
||||
</uui-box>`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<uui-checkbox
|
||||
@change=${this.#onSelectAllChange}
|
||||
label=${this.localize.term('general_selectAll')}
|
||||
.checked=${this._isAllSelected}></uui-checkbox>
|
||||
${repeat(
|
||||
this.variantLanguageOptions,
|
||||
(option) => option.unique,
|
||||
(option) => html` ${this.#renderItem(option)} `,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderItem(option: UmbDocumentVariantOptionModel) {
|
||||
@@ -135,6 +167,14 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement {
|
||||
.label-status {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
uui-menu-item {
|
||||
--uui-menu-item-flat-structure: 1;
|
||||
}
|
||||
|
||||
uui-checkbox {
|
||||
margin-bottom: var(--uui-size-space-3);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -76,9 +76,10 @@ export class UmbLogViewerLogLevelFilterMenuElement extends UmbLitElement {
|
||||
<umb-log-viewer-level-tag .level=${logLevel}></umb-log-viewer-level-tag>
|
||||
</uui-checkbox>`,
|
||||
)}
|
||||
<uui-button class="log-level-menu-item" @click=${this.#selectAllLogLevels} label="Select all"
|
||||
>Select all</uui-button
|
||||
>
|
||||
<uui-button
|
||||
class="log-level-menu-item"
|
||||
@click=${this.#selectAllLogLevels}
|
||||
label=${this.localize.term('general_selectAll')}></uui-button>
|
||||
<uui-button class="log-level-menu-item" @click=${this.#deselectAllLogLevels} label="Deselect all"
|
||||
>Deselect all</uui-button
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user