diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts
index 8b876086c390..22cda2c9b219 100644
--- a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts
+++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts
@@ -1412,14 +1412,14 @@ export default {
cssSavedText: 'Stylesheet saved without any errors',
dataTypeSaved: 'Datatype saved',
dictionaryItemSaved: 'Dictionary item saved',
- editContentPublishedHeader: 'Content published',
+ editContentPublishedHeader: 'Document published',
editContentPublishedText: 'and is visible on the website',
- editMultiContentPublishedText: '%0% documents published and visible on the website',
- editVariantPublishedText: '%0% published and visible on the website',
- editMultiVariantPublishedText: '%0% documents published for languages %1% and visible on the website',
+ editMultiContentPublishedText: '%0% documents published and are visible on the website',
+ editVariantPublishedText: '%0% published and is visible on the website',
+ editMultiVariantPublishedText: '%0% documents published for languages %1% and are visible on the website',
editBlueprintSavedHeader: 'Document Blueprint saved',
editBlueprintSavedText: 'Changes have been successfully saved',
- editContentSavedHeader: 'Content saved',
+ editContentSavedHeader: 'Document saved',
editContentSavedText: 'Remember to publish to make changes visible',
editContentScheduledSavedText: 'A schedule for publishing has been updated',
editVariantSavedText: '%0% saved',
diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
index 40c1be0e3f3e..3dd24d3ce59f 100644
--- a/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
+++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en.ts
@@ -1412,7 +1412,7 @@ export default {
folderUploadNotAllowed:
'This file is being uploaded as part of a folder, but creating a new folder is not allowed here',
folderCreationNotAllowed: 'Creating a new folder is not allowed here',
- contentPublishedFailedByEvent: 'Content could not be published, a 3rd party add-in cancelled the action',
+ contentPublishedFailedByEvent: 'Document could not be published, a 3rd party add-in cancelled the action',
contentTypeDublicatePropertyType: 'Property type already exists',
contentTypePropertyTypeCreated: 'Property type created',
contentTypePropertyTypeCreatedText: 'Name: %0% DataType: %1%',
@@ -1426,12 +1426,13 @@ export default {
cssSavedText: 'Stylesheet saved without any errors',
dataTypeSaved: 'Datatype saved',
dictionaryItemSaved: 'Dictionary item saved',
- editContentPublishedFailedByParent: 'Content could not be published, because a parent page is not published',
- editContentPublishedHeader: 'Content published',
- editContentPublishedText: 'and visible on the website',
+ editContentPublishedFailedByValidation: 'Document could not be published, but we saved it for you',
+ editContentPublishedFailedByParent: 'Document could not be published, because a parent page is not published',
+ editContentPublishedHeader: 'Document published',
+ editContentPublishedText: 'and is visible on the website',
editBlueprintSavedHeader: 'Document Blueprint saved',
editBlueprintSavedText: 'Changes have been successfully saved',
- editContentSavedHeader: 'Content saved',
+ editContentSavedHeader: 'Document saved',
editContentSavedText: 'Remember to publish to make changes visible',
editContentSendToPublish: 'Sent For Approval',
editContentSendToPublishText: 'Changes have been sent for approval',
@@ -1493,10 +1494,11 @@ export default {
cannotCopyInformation: 'Could not copy your system information to the clipboard',
webhookSaved: 'Webhook saved',
operationSavedHeaderReloadUser: 'Saved. To view the changes please reload your browser',
- editMultiContentPublishedText: '%0% documents published and visible on the website',
- editVariantPublishedText: '%0% published and visible on the website',
- editMultiVariantPublishedText: '%0% documents published for languages %1% and visible on the website',
+ editMultiContentPublishedText: '%0% documents published and are visible on the website',
+ editVariantPublishedText: '%0% published and is visible on the website',
+ editMultiVariantPublishedText: '%0% documents published for languages %1% and are visible on the website',
editContentScheduledSavedText: 'A schedule for publishing has been updated',
+ editContentScheduledNotSavedText: 'The schedule for publishing could not be updated',
editVariantSavedText: '%0% saved',
editVariantSendToPublishText: '%0% changes have been sent for approval',
contentCultureUnpublished: 'Content variation %0% unpublished',
diff --git a/src/Umbraco.Web.UI.Client/src/libs/localization-api/localization.controller.test.ts b/src/Umbraco.Web.UI.Client/src/libs/localization-api/localization.controller.test.ts
index 24c2a0d331a4..bb1376e6a848 100644
--- a/src/Umbraco.Web.UI.Client/src/libs/localization-api/localization.controller.test.ts
+++ b/src/Umbraco.Web.UI.Client/src/libs/localization-api/localization.controller.test.ts
@@ -282,6 +282,16 @@ describe('UmbLocalizeController', () => {
});
});
+ describe('list format', () => {
+ it('should return a list with conjunction', () => {
+ expect(controller.list(['one', 'two', 'three'], { type: 'conjunction' })).to.equal('one, two, and three');
+ });
+
+ it('should return a list with disjunction', () => {
+ expect(controller.list(['one', 'two', 'three'], { type: 'disjunction' })).to.equal('one, two, or three');
+ });
+ });
+
describe('duration', () => {
it('should return a duration', () => {
const now = new Date('2020-01-01T00:00:00');
diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts
index 0e8b63935a5e..28ca8df5ea61 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts
@@ -941,8 +941,16 @@ export const data: Array = [
{
alias: 'layouts',
value: [
- { icon: 'icon-grid', isSystem: true, name: 'Grid', path: '', selected: true },
- { icon: 'icon-list', isSystem: true, name: 'Table', path: '', selected: true },
+ {
+ icon: 'icon-grid',
+ name: 'Document Grid Collection View',
+ collectionView: 'Umb.CollectionView.Document.Grid',
+ },
+ {
+ icon: 'icon-list',
+ name: 'Document Table Collection View',
+ collectionView: 'Umb.CollectionView.Document.Table',
+ },
],
},
{ alias: 'icon', value: 'icon-layers' },
diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts
index df508ed15e88..f420b115fe03 100644
--- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts
+++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts
@@ -41,6 +41,13 @@ export const detailHandlers = [
return res(ctx.status(200), ctx.json(PagedTrackedReference));
}),
+ rest.put(umbracoPath(`${UMB_SLUG}/:id/validate`, 'v1.1'), (_req, res, ctx) => {
+ const id = _req.params.id as string;
+ if (!id) return res(ctx.status(400));
+
+ return res(ctx.status(200));
+ }),
+
rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return res(ctx.status(400));
diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/umbraco-path.function.ts b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/umbraco-path.function.ts
index 754e07d3a947..9466adb7c34b 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/umbraco-path.function.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/core/utils/path/umbraco-path.function.ts
@@ -1,8 +1,10 @@
// TODO: Rename to something more obvious, naming wise this can mean anything. I suggest: umbracoManagementApiPath()
/**
- *
- * @param path
+ * Generates a path to an Umbraco API endpoint.
+ * @param {string} path - The path to the Umbraco API endpoint.
+ * @param {string} version - The version of the Umbraco API (default is 'v1').
+ * @returns {string} The path to the Umbraco API endpoint.
*/
-export function umbracoPath(path: string) {
- return `/umbraco/management/api/v1${path}`;
+export function umbracoPath(path: string, version = 'v1') {
+ return `/umbraco/management/api/${version}${path}`;
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts
index e74be197226a..098993fc23e2 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-action/publish.action.ts
@@ -10,6 +10,8 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import { UMB_CURRENT_USER_CONTEXT } from '@umbraco-cms/backoffice/current-user';
+import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
+import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
export class UmbPublishDocumentEntityAction extends UmbEntityActionBase {
constructor(host: UmbControllerHost, args: UmbEntityActionArgs) {
@@ -19,6 +21,9 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase {
override async execute() {
if (!this.args.unique) throw new Error('The document unique identifier is missing');
+ const notificationContext = await this.getContext(UMB_NOTIFICATION_CONTEXT);
+ const localize = new UmbLocalizationController(this);
+
const languageRepository = new UmbLanguageCollectionRepository(this._host);
const { data: languageData } = await languageRepository.requestCollection({});
@@ -65,7 +70,15 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase {
if (options.length === 1) {
const variantId = UmbVariantId.Create(documentData.variants[0]);
const publishingRepository = new UmbDocumentPublishingRepository(this._host);
- await publishingRepository.publish(this.args.unique, [{ variantId }]);
+ const { error } = await publishingRepository.publish(this.args.unique, [{ variantId }]);
+ if (!error) {
+ notificationContext.peek('positive', {
+ data: {
+ headline: localize.term('speechBubbles_editContentPublishedHeader'),
+ message: localize.term('speechBubbles_editContentPublishedText'),
+ },
+ });
+ }
actionEventContext.dispatchEvent(event);
return;
}
@@ -103,10 +116,24 @@ export class UmbPublishDocumentEntityAction extends UmbEntityActionBase {
if (variantIds.length) {
const publishingRepository = new UmbDocumentPublishingRepository(this._host);
- await publishingRepository.publish(
+ const { error } = await publishingRepository.publish(
this.args.unique,
variantIds.map((variantId) => ({ variantId })),
);
+
+ if (!error) {
+ const documentVariants = documentData.variants.filter((variant) => result.selection.includes(variant.culture!));
+ notificationContext.peek('positive', {
+ data: {
+ headline: localize.term('speechBubbles_editContentPublishedHeader'),
+ message: localize.term(
+ 'speechBubbles_editVariantPublishedText',
+ localize.list(documentVariants.map((v) => v.culture ?? v.name)),
+ ),
+ },
+ });
+ }
+
actionEventContext.dispatchEvent(event);
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts
index 7c2d18292601..014946c962af 100644
--- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts
+++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/publishing/publish/entity-bulk-action/publish.bulk-action.ts
@@ -11,6 +11,7 @@ import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-
import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action';
+import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
export class UmbDocumentPublishEntityBulkAction extends UmbEntityBulkActionBase