Merge branch 'v15/dev' into v16/dev
This commit is contained in:
@@ -593,8 +593,8 @@ stages:
|
||||
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
|
||||
|
||||
# Install Playwright and dependencies
|
||||
- pwsh: npx playwright install --with-deps
|
||||
displayName: Install Playwright
|
||||
- pwsh: npx playwright install chromium
|
||||
displayName: Install Playwright only with Chromium browser
|
||||
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
|
||||
|
||||
# Test
|
||||
@@ -760,8 +760,8 @@ stages:
|
||||
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
|
||||
|
||||
# Install Playwright and dependencies
|
||||
- pwsh: npx playwright install --with-deps
|
||||
displayName: Install Playwright
|
||||
- pwsh: npx playwright install chromium
|
||||
displayName: Install Playwright only with Chromium browser
|
||||
workingDirectory: tests/Umbraco.Tests.AcceptanceTest
|
||||
|
||||
# Test
|
||||
|
||||
@@ -69,11 +69,6 @@ public class PublishDocumentWithDescendantsController : DocumentControllerBase
|
||||
publishBranchFilter |= PublishBranchFilter.IncludeUnpublished;
|
||||
}
|
||||
|
||||
if (requestModel.ForceRepublish)
|
||||
{
|
||||
publishBranchFilter |= PublishBranchFilter.ForceRepublish;
|
||||
}
|
||||
|
||||
return publishBranchFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42851,7 +42851,6 @@
|
||||
"PublishDocumentWithDescendantsRequestModel": {
|
||||
"required": [
|
||||
"cultures",
|
||||
"forceRepublish",
|
||||
"includeUnpublishedDescendants"
|
||||
],
|
||||
"type": "object",
|
||||
@@ -42859,9 +42858,6 @@
|
||||
"includeUnpublishedDescendants": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"forceRepublish": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"cultures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -4,7 +4,5 @@ public class PublishDocumentWithDescendantsRequestModel
|
||||
{
|
||||
public bool IncludeUnpublishedDescendants { get; set; }
|
||||
|
||||
public bool ForceRepublish { get; set; }
|
||||
|
||||
public required IEnumerable<string> Cultures { get; set; }
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ public class PackageManifest
|
||||
|
||||
public bool AllowTelemetry { get; set; } = true;
|
||||
|
||||
[Obsolete("Use AllowTelemetry instead. This property will be removed in future versions.")]
|
||||
public bool AllowPackageTelemetry { get; set; } = true;
|
||||
|
||||
public required object[] Extensions { get; set; }
|
||||
|
||||
public PackageManifestImportmap? Importmap { get; set; }
|
||||
|
||||
@@ -29,7 +29,7 @@ public interface ITwoFactorLoginService : IService
|
||||
/// The returned type can be anything depending on the setup providers. You will need to cast it to the type handled by
|
||||
/// the provider.
|
||||
/// </remarks>
|
||||
[Obsolete("Use IUserTwoFactorLoginService.GetSetupInfoWithStatusAsync. This will be removed in Umbraco 15.")]
|
||||
[Obsolete("Use IUserTwoFactorLoginService.GetSetupInfoAsync. This will be removed in Umbraco 15.")]
|
||||
Task<object?> GetSetupInfoAsync(Guid userOrMemberKey, string providerName);
|
||||
|
||||
/// <summary>
|
||||
@@ -60,13 +60,13 @@ public interface ITwoFactorLoginService : IService
|
||||
/// <summary>
|
||||
/// Disables 2FA with Code.
|
||||
/// </summary>
|
||||
[Obsolete("Use IUserTwoFactorLoginService.DisableByCodeWithStatusAsync. This will be removed in Umbraco 15.")]
|
||||
[Obsolete("Use IUserTwoFactorLoginService.DisableByCodeAsync. This will be removed in Umbraco 15.")]
|
||||
Task<bool> DisableWithCodeAsync(string providerName, Guid userOrMemberKey, string code);
|
||||
|
||||
/// <summary>
|
||||
/// Validates and Saves.
|
||||
/// </summary>
|
||||
[Obsolete("Use IUserTwoFactorLoginService.ValidateAndSaveWithStatusAsync. This will be removed in Umbraco 15.")]
|
||||
[Obsolete("Use IUserTwoFactorLoginService.ValidateAndSaveAsync. This will be removed in Umbraco 15.")]
|
||||
Task<bool> ValidateAndSaveAsync(string providerName, Guid userKey, string secret, string code);
|
||||
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ public class PackagingService : IPackagingService
|
||||
}
|
||||
|
||||
// Set additional values
|
||||
installedPackage.AllowPackageTelemetry = packageManifest.AllowTelemetry;
|
||||
installedPackage.AllowPackageTelemetry = packageManifest is { AllowTelemetry: true, AllowPackageTelemetry: true };
|
||||
|
||||
if (!string.IsNullOrEmpty(packageManifest.Version))
|
||||
{
|
||||
|
||||
@@ -173,8 +173,8 @@
|
||||
"generate:icons": "node ./devops/icons/index.js",
|
||||
"generate:overrides": "node ./devops/tsc/index.js",
|
||||
"generate:jsonschema:imports": "node ./devops/json-schema-generator/index.js",
|
||||
"generate:jsonschema:dist": "typescript-json-schema --required --include \"./src/json-schema/umbraco-package-schema.ts\" --out dist-cms/umbraco-package-schema.json tsconfig.json UmbracoPackage",
|
||||
"generate:jsonschema": "typescript-json-schema --required --include \"./src/json-schema/umbraco-package-schema.ts\"",
|
||||
"generate:jsonschema:dist": "npm run generate:jsonschema -- --out dist-cms/umbraco-package-schema.json tsconfig.json UmbracoPackage",
|
||||
"generate:jsonschema": "typescript-json-schema --skipLibCheck --ignoreErrors --excludePrivate --required --include \"./src/json-schema/umbraco-package-schema.ts\"",
|
||||
"generate:check-const-test": "node ./devops/generate-check-const-test/index.js",
|
||||
"lint:errors": "npm run lint -- --quiet",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
|
||||
@@ -298,9 +298,6 @@ export default {
|
||||
removeTextBox: 'Fjern denne tekstboks',
|
||||
contentRoot: 'Indholdsrod',
|
||||
includeUnpublished: 'Inkluder ikke-udgivet indhold.',
|
||||
forceRepublish: 'Udgiv uændrede elementer.',
|
||||
forceRepublishWarning: 'ADVARSEL: Udgivelse af alle sider under denne i indholdstræet, uanset om de er ændret eller ej, kan være en ressourcekrævende og langvarig proces.',
|
||||
forceRepublishAdvisory: 'Dette bør ikke være nødvendigt under normale omstændigheder, så fortsæt kun med denne handling, hvis du er sikker på, at det er nødvendigt.',
|
||||
isSensitiveValue:
|
||||
'Denne værdi er skjult.Hvis du har brug for adgang til at se denne værdi, bedes du\n kontakte din web-administrator.\n ',
|
||||
isSensitiveValue_short: 'Denne værdi er skjult.',
|
||||
|
||||
@@ -320,9 +320,6 @@ export default {
|
||||
removeTextBox: 'Remove this text box',
|
||||
contentRoot: 'Content root',
|
||||
includeUnpublished: 'Include unpublished content items.',
|
||||
forceRepublish: 'Publish unchanged items.',
|
||||
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
||||
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
||||
isSensitiveValue:
|
||||
'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
||||
isSensitiveValue_short: 'This value is hidden.',
|
||||
|
||||
@@ -317,9 +317,6 @@ export default {
|
||||
removeTextBox: 'Remove this text box',
|
||||
contentRoot: 'Content root',
|
||||
includeUnpublished: 'Include unpublished content items.',
|
||||
forceRepublish: 'Publish unchanged items.',
|
||||
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
||||
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
||||
isSensitiveValue:
|
||||
'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
||||
isSensitiveValue_short: 'This value is hidden.',
|
||||
|
||||
@@ -2050,7 +2050,6 @@ export type PublishDocumentRequestModel = {
|
||||
|
||||
export type PublishDocumentWithDescendantsRequestModel = {
|
||||
includeUnpublishedDescendants: boolean;
|
||||
forceRepublish: boolean;
|
||||
cultures: Array<(string)>;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,18 +6,18 @@ import styles from 'monaco-editor/min/vs/editor/editor.main.css?inline';
|
||||
const initializeWorkers = () => {
|
||||
self.MonacoEnvironment = {
|
||||
getWorker(workerId: string, label: string): Promise<Worker> | Worker {
|
||||
let url = '/umbraco/backoffice/monaco-editor/esm/vs/editor/editor.worker.js';
|
||||
let url = '/umbraco/backoffice/monaco-editor/vs/editor/editor.worker.js';
|
||||
if (label === 'json') {
|
||||
url = '/umbraco/backoffice/monaco-editor/esm/vs/language/json/json.worker.js';
|
||||
url = '/umbraco/backoffice/monaco-editor/vs/language/json/json.worker.js';
|
||||
}
|
||||
if (label === 'css' || label === 'scss' || label === 'less') {
|
||||
url = '/umbraco/backoffice/monaco-editor/esm/vs/language/css/css.worker.js';
|
||||
url = '/umbraco/backoffice/monaco-editor/vs/language/css/css.worker.js';
|
||||
}
|
||||
if (label === 'html' || label === 'handlebars' || label === 'razor') {
|
||||
url = '/umbraco/backoffice/monaco-editor/esm/vs/language/html/html.worker.js';
|
||||
url = '/umbraco/backoffice/monaco-editor/vs/language/html/html.worker.js';
|
||||
}
|
||||
if (label === 'typescript' || label === 'javascript') {
|
||||
url = '/umbraco/backoffice/monaco-editor/esm/vs/language/typescript/ts.worker.js';
|
||||
url = '/umbraco/backoffice/monaco-editor/vs/language/typescript/ts.worker.js';
|
||||
}
|
||||
return new Worker(url, { name: workerId, type: 'module' });
|
||||
},
|
||||
|
||||
@@ -25,6 +25,9 @@ export function renderEditor(userConfig?: RawEditorOptions) {
|
||||
// Declare a global variable to hold the TinyMCE instance
|
||||
declare global {
|
||||
interface Window {
|
||||
/**
|
||||
* @TJS-ignore
|
||||
*/
|
||||
tinymce: TinyMCE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
import '@umbraco-cms/backoffice/app';
|
||||
import '@umbraco-cms/backoffice/class-api';
|
||||
import '@umbraco-cms/backoffice/context-api';
|
||||
import '@umbraco-cms/backoffice/controller-api';
|
||||
import '@umbraco-cms/backoffice/element-api';
|
||||
import '@umbraco-cms/backoffice/embedded-media';
|
||||
import '@umbraco-cms/backoffice/extension-api';
|
||||
import '@umbraco-cms/backoffice/formatting-api';
|
||||
import '@umbraco-cms/backoffice/localization-api';
|
||||
import '@umbraco-cms/backoffice/observable-api';
|
||||
import '@umbraco-cms/backoffice/action';
|
||||
import '@umbraco-cms/backoffice/audit-log';
|
||||
import '@umbraco-cms/backoffice/auth';
|
||||
import '@umbraco-cms/backoffice/block-custom-view';
|
||||
import '@umbraco-cms/backoffice/block-grid';
|
||||
import '@umbraco-cms/backoffice/block-list';
|
||||
import '@umbraco-cms/backoffice/block-rte';
|
||||
import '@umbraco-cms/backoffice/block-type';
|
||||
import '@umbraco-cms/backoffice/block';
|
||||
import '@umbraco-cms/backoffice/code-editor';
|
||||
import '@umbraco-cms/backoffice/collection';
|
||||
import '@umbraco-cms/backoffice/components';
|
||||
import '@umbraco-cms/backoffice/content-type';
|
||||
import '@umbraco-cms/backoffice/content';
|
||||
import '@umbraco-cms/backoffice/culture';
|
||||
import '@umbraco-cms/backoffice/current-user';
|
||||
import '@umbraco-cms/backoffice/dashboard';
|
||||
import '@umbraco-cms/backoffice/data-type';
|
||||
import '@umbraco-cms/backoffice/debug';
|
||||
import '@umbraco-cms/backoffice/dictionary';
|
||||
import '@umbraco-cms/backoffice/document-blueprint';
|
||||
import '@umbraco-cms/backoffice/document-type';
|
||||
import '@umbraco-cms/backoffice/document';
|
||||
import '@umbraco-cms/backoffice/entity-action';
|
||||
import '@umbraco-cms/backoffice/entity-bulk-action';
|
||||
import '@umbraco-cms/backoffice/entity-create-option-action';
|
||||
import '@umbraco-cms/backoffice/entity';
|
||||
import '@umbraco-cms/backoffice/event';
|
||||
import '@umbraco-cms/backoffice/extension-registry';
|
||||
import '@umbraco-cms/backoffice/health-check';
|
||||
import '@umbraco-cms/backoffice/help';
|
||||
import '@umbraco-cms/backoffice/icon';
|
||||
import '@umbraco-cms/backoffice/id';
|
||||
import '@umbraco-cms/backoffice/imaging';
|
||||
import '@umbraco-cms/backoffice/language';
|
||||
import '@umbraco-cms/backoffice/lit-element';
|
||||
import '@umbraco-cms/backoffice/localization';
|
||||
import '@umbraco-cms/backoffice/log-viewer';
|
||||
import '@umbraco-cms/backoffice/markdown-editor';
|
||||
import '@umbraco-cms/backoffice/media-type';
|
||||
import '@umbraco-cms/backoffice/media';
|
||||
import '@umbraco-cms/backoffice/member-group';
|
||||
import '@umbraco-cms/backoffice/member-type';
|
||||
import '@umbraco-cms/backoffice/member';
|
||||
import '@umbraco-cms/backoffice/menu';
|
||||
import '@umbraco-cms/backoffice/modal';
|
||||
import '@umbraco-cms/backoffice/multi-url-picker';
|
||||
import '@umbraco-cms/backoffice/notification';
|
||||
import '@umbraco-cms/backoffice/object-type';
|
||||
import '@umbraco-cms/backoffice/package';
|
||||
import '@umbraco-cms/backoffice/partial-view';
|
||||
import '@umbraco-cms/backoffice/picker-input';
|
||||
import '@umbraco-cms/backoffice/picker';
|
||||
import '@umbraco-cms/backoffice/property-action';
|
||||
import '@umbraco-cms/backoffice/property-editor';
|
||||
import '@umbraco-cms/backoffice/property-type';
|
||||
import '@umbraco-cms/backoffice/property';
|
||||
import '@umbraco-cms/backoffice/recycle-bin';
|
||||
import '@umbraco-cms/backoffice/relation-type';
|
||||
import '@umbraco-cms/backoffice/relations';
|
||||
import '@umbraco-cms/backoffice/repository';
|
||||
import '@umbraco-cms/backoffice/resources';
|
||||
import '@umbraco-cms/backoffice/router';
|
||||
import '@umbraco-cms/backoffice/rte';
|
||||
import '@umbraco-cms/backoffice/script';
|
||||
import '@umbraco-cms/backoffice/search';
|
||||
import '@umbraco-cms/backoffice/section';
|
||||
import '@umbraco-cms/backoffice/server-file-system';
|
||||
import '@umbraco-cms/backoffice/settings';
|
||||
import '@umbraco-cms/backoffice/sorter';
|
||||
import '@umbraco-cms/backoffice/static-file';
|
||||
import '@umbraco-cms/backoffice/store';
|
||||
import '@umbraco-cms/backoffice/style';
|
||||
import '@umbraco-cms/backoffice/stylesheet';
|
||||
import '@umbraco-cms/backoffice/sysinfo';
|
||||
import '@umbraco-cms/backoffice/tags';
|
||||
import '@umbraco-cms/backoffice/template';
|
||||
import '@umbraco-cms/backoffice/temporary-file';
|
||||
import '@umbraco-cms/backoffice/themes';
|
||||
import '@umbraco-cms/backoffice/tiny-mce';
|
||||
import '@umbraco-cms/backoffice/tiptap';
|
||||
import '@umbraco-cms/backoffice/translation';
|
||||
import '@umbraco-cms/backoffice/tree';
|
||||
import '@umbraco-cms/backoffice/ufm';
|
||||
import '@umbraco-cms/backoffice/user-change-password';
|
||||
import '@umbraco-cms/backoffice/user-group';
|
||||
import '@umbraco-cms/backoffice/user-permission';
|
||||
import '@umbraco-cms/backoffice/user';
|
||||
import '@umbraco-cms/backoffice/utils';
|
||||
import '@umbraco-cms/backoffice/validation';
|
||||
import '@umbraco-cms/backoffice/variant';
|
||||
import '@umbraco-cms/backoffice/webhook';
|
||||
import '@umbraco-cms/backoffice/workspace';
|
||||
import '@umbraco-cms/backoffice/external/backend-api';
|
||||
import '@umbraco-cms/backoffice/external/base64-js';
|
||||
import '@umbraco-cms/backoffice/external/diff';
|
||||
import '@umbraco-cms/backoffice/external/dompurify';
|
||||
import '@umbraco-cms/backoffice/external/lit';
|
||||
import '@umbraco-cms/backoffice/external/marked';
|
||||
import '@umbraco-cms/backoffice/external/monaco-editor';
|
||||
import '@umbraco-cms/backoffice/external/openid';
|
||||
import '@umbraco-cms/backoffice/external/router-slot';
|
||||
import '@umbraco-cms/backoffice/external/rxjs';
|
||||
import '@umbraco-cms/backoffice/external/tinymce';
|
||||
import '@umbraco-cms/backoffice/external/tiptap';
|
||||
import '@umbraco-cms/backoffice/external/uui';
|
||||
import '@umbraco-cms/backoffice/external/uuid';
|
||||
@@ -1,4 +1,4 @@
|
||||
import './all-packages.js';
|
||||
import '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
/**
|
||||
* Umbraco package manifest JSON
|
||||
@@ -27,6 +27,13 @@ export interface UmbracoPackage {
|
||||
*/
|
||||
allowTelemetry?: boolean;
|
||||
|
||||
/**
|
||||
* @title Decides if the package sends telemetry data for collection
|
||||
* @default true
|
||||
* @deprecated Use allowTelemetry instead
|
||||
*/
|
||||
allowPackageTelemetry?: boolean;
|
||||
|
||||
/**
|
||||
* @title Decides if the package is allowed to be accessed by the public, e.g. on the login screen
|
||||
* @default false
|
||||
|
||||
@@ -16,6 +16,7 @@ export class UmbMoveToEntityAction extends UmbEntityActionBase<MetaEntityActionM
|
||||
data: {
|
||||
treeAlias: this.args.meta.treeAlias,
|
||||
foldersOnly: this.args.meta.foldersOnly,
|
||||
pickableFilter: (treeItem) => treeItem.unique !== this.args.unique,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { UmbTreeStartNode } from '../types.js';
|
||||
import type { UmbTreeItemModel, UmbTreeStartNode } from '../types.js';
|
||||
import { UMB_TREE_PICKER_MODAL_ALIAS } from './constants.js';
|
||||
import type { UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbWorkspaceModalData } from '@umbraco-cms/backoffice/workspace';
|
||||
@@ -14,7 +14,7 @@ export interface UmbTreePickerModalCreateActionData<PathPatternParamsType extend
|
||||
}
|
||||
|
||||
export interface UmbTreePickerModalData<
|
||||
TreeItemType,
|
||||
TreeItemType = UmbTreeItemModel,
|
||||
PathPatternParamsType extends UmbPathPatternParamsType = UmbPathPatternParamsType,
|
||||
> extends UmbPickerModalData<TreeItemType> {
|
||||
hideTreeRoot?: boolean;
|
||||
@@ -28,7 +28,7 @@ export interface UmbTreePickerModalData<
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface UmbTreePickerModalValue extends UmbPickerModalValue {}
|
||||
|
||||
export const UMB_TREE_PICKER_MODAL = new UmbModalToken<UmbTreePickerModalData<unknown>, UmbTreePickerModalValue>(
|
||||
export const UMB_TREE_PICKER_MODAL = new UmbModalToken<UmbTreePickerModalData, UmbTreePickerModalValue>(
|
||||
UMB_TREE_PICKER_MODAL_ALIAS,
|
||||
{
|
||||
modal: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
UmbDocumentPublishWithDescendantsModalValue,
|
||||
} from './document-publish-with-descendants-modal.token.js';
|
||||
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { umbConfirmModal, UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
@@ -18,7 +18,6 @@ export class UmbDocumentPublishWithDescendantsModalElement extends UmbModalBaseE
|
||||
> {
|
||||
#selectionManager = new UmbSelectionManager<string>(this);
|
||||
#includeUnpublishedDescendants = false;
|
||||
#forceRepublish = false;
|
||||
|
||||
@state()
|
||||
_options: Array<UmbDocumentVariantOptionModel> = [];
|
||||
@@ -84,25 +83,11 @@ export class UmbDocumentPublishWithDescendantsModalElement extends UmbModalBaseE
|
||||
this.#includeUnpublishedDescendants = !this.#includeUnpublishedDescendants;
|
||||
}
|
||||
|
||||
async #onForceRepublishChange() {
|
||||
this.#forceRepublish = !this.#forceRepublish;
|
||||
}
|
||||
|
||||
async #submit() {
|
||||
|
||||
if (this.#forceRepublish) {
|
||||
await umbConfirmModal(this, {
|
||||
headline: this.localize.term('content_forceRepublishWarning'),
|
||||
content: this.localize.term('content_forceRepublishAdvisory'),
|
||||
color: 'warning',
|
||||
confirmLabel: this.localize.term('actions_publish'),
|
||||
});
|
||||
}
|
||||
|
||||
this.value = {
|
||||
selection: this.#selectionManager.getSelection(),
|
||||
includeUnpublishedDescendants: this.#includeUnpublishedDescendants,
|
||||
forceRepublish: this.#forceRepublish,
|
||||
};
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
@@ -143,14 +128,6 @@ export class UmbDocumentPublishWithDescendantsModalElement extends UmbModalBaseE
|
||||
@change=${this.#onIncludeUnpublishedDescendantsChange}></uui-toggle>
|
||||
</uui-form-layout-item>
|
||||
|
||||
<uui-form-layout-item>
|
||||
<uui-toggle
|
||||
id="forceRepublish"
|
||||
label=${this.localize.term('content_forceRepublish')}
|
||||
?checked=${this.value?.forceRepublish}
|
||||
@change=${this.#onForceRepublishChange}></uui-toggle>
|
||||
</uui-form-layout-item>
|
||||
|
||||
<div slot="actions">
|
||||
<uui-button label=${this.localize.term('general_close')} @click=${this.#close}></uui-button>
|
||||
<uui-button
|
||||
|
||||
@@ -8,7 +8,6 @@ export interface UmbDocumentPublishWithDescendantsModalData extends UmbDocumentV
|
||||
|
||||
export interface UmbDocumentPublishWithDescendantsModalValue extends UmbDocumentVariantPickerValue {
|
||||
includeUnpublishedDescendants?: boolean;
|
||||
forceRepublish?: boolean;
|
||||
}
|
||||
|
||||
export const UMB_DOCUMENT_PUBLISH_WITH_DESCENDANTS_MODAL = new UmbModalToken<
|
||||
|
||||
@@ -71,14 +71,12 @@ export class UmbDocumentPublishingRepository extends UmbRepositoryBase {
|
||||
* @param id
|
||||
* @param variantIds
|
||||
* @param includeUnpublishedDescendants
|
||||
* @param forceRepublish
|
||||
* @memberof UmbDocumentPublishingRepository
|
||||
*/
|
||||
async publishWithDescendants(
|
||||
id: string,
|
||||
variantIds: Array<UmbVariantId>,
|
||||
includeUnpublishedDescendants: boolean,
|
||||
forceRepublish: boolean,
|
||||
) {
|
||||
if (!id) throw new Error('id is missing');
|
||||
if (!variantIds) throw new Error('variant IDs are missing');
|
||||
@@ -88,7 +86,6 @@ export class UmbDocumentPublishingRepository extends UmbRepositoryBase {
|
||||
id,
|
||||
variantIds,
|
||||
includeUnpublishedDescendants,
|
||||
forceRepublish,
|
||||
);
|
||||
|
||||
if (!error) {
|
||||
|
||||
@@ -92,21 +92,18 @@ export class UmbDocumentPublishingServerDataSource {
|
||||
* @param unique
|
||||
* @param variantIds
|
||||
* @param includeUnpublishedDescendants
|
||||
* @param forceRepublish
|
||||
* @memberof UmbDocumentPublishingServerDataSource
|
||||
*/
|
||||
async publishWithDescendants(
|
||||
unique: string,
|
||||
variantIds: Array<UmbVariantId>,
|
||||
includeUnpublishedDescendants: boolean,
|
||||
forceRepublish: boolean,
|
||||
) {
|
||||
if (!unique) throw new Error('Id is missing');
|
||||
|
||||
const requestBody: PublishDocumentWithDescendantsRequestModel = {
|
||||
cultures: variantIds.map((variant) => variant.toCultureString()),
|
||||
includeUnpublishedDescendants,
|
||||
forceRepublish,
|
||||
};
|
||||
|
||||
return tryExecuteAndNotify(
|
||||
|
||||
@@ -229,7 +229,6 @@ export class UmbDocumentPublishingWorkspaceContext extends UmbContextBase<UmbDoc
|
||||
unique,
|
||||
variantIds,
|
||||
result.includeUnpublishedDescendants ?? false,
|
||||
result.forceRepublish ?? false,
|
||||
);
|
||||
|
||||
if (!error) {
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import { css, html, nothing, repeat, customElement, property, classMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { classMap, css, customElement, html, nothing, property, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
export type UmbCheckboxListItem = { label: string; value: string; checked: boolean; invalid?: boolean };
|
||||
|
||||
@customElement('umb-input-checkbox-list')
|
||||
export class UmbInputCheckboxListElement extends UUIFormControlMixin(UmbLitElement, '') {
|
||||
export class UmbInputCheckboxListElement extends UmbFormControlMixin<
|
||||
string | undefined,
|
||||
typeof UmbLitElement,
|
||||
undefined
|
||||
>(UmbLitElement, undefined) {
|
||||
@property({ attribute: false })
|
||||
public list: Array<UmbCheckboxListItem> = [];
|
||||
|
||||
@@ -38,8 +42,24 @@ export class UmbInputCheckboxListElement extends UUIFormControlMixin(UmbLitEleme
|
||||
@property({ type: Boolean, reflect: true })
|
||||
readonly = false;
|
||||
|
||||
protected override getFormElement() {
|
||||
return undefined;
|
||||
/**
|
||||
* Sets the input to required, meaning validation will fail if the value is empty.
|
||||
* @type {boolean}
|
||||
*/
|
||||
@property({ type: Boolean })
|
||||
required?: boolean;
|
||||
|
||||
@property({ type: String })
|
||||
requiredMessage?: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addValidator(
|
||||
'valueMissing',
|
||||
() => this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY,
|
||||
() => !this.readonly && !!this.required && (this.value === undefined || this.value === null || this.value === ''),
|
||||
);
|
||||
}
|
||||
|
||||
#onChange(event: UUIBooleanInputEvent) {
|
||||
@@ -73,13 +93,15 @@ export class UmbInputCheckboxListElement extends UUIFormControlMixin(UmbLitEleme
|
||||
}
|
||||
|
||||
#renderCheckbox(item: (typeof this.list)[0]) {
|
||||
return html`<uui-checkbox
|
||||
return html`
|
||||
<uui-checkbox
|
||||
class=${classMap({ invalid: !!item.invalid })}
|
||||
?checked=${item.checked}
|
||||
label=${item.label + (item.invalid ? ` (${this.localize.term('validation_legacyOption')})` : '')}
|
||||
title=${item.invalid ? this.localize.term('validation_legacyOptionDescription') : ''}
|
||||
value=${item.value}
|
||||
?readonly=${this.readonly}></uui-checkbox>`;
|
||||
?checked=${item.checked}
|
||||
?readonly=${this.readonly}></uui-checkbox>
|
||||
`;
|
||||
}
|
||||
|
||||
static override readonly styles = [
|
||||
|
||||
@@ -2,28 +2,35 @@ import type {
|
||||
UmbCheckboxListItem,
|
||||
UmbInputCheckboxListElement,
|
||||
} from './components/input-checkbox-list/input-checkbox-list.element.js';
|
||||
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
import type {
|
||||
UmbPropertyEditorConfigCollection,
|
||||
UmbPropertyEditorUiElement,
|
||||
} from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
import './components/input-checkbox-list/input-checkbox-list.element.js';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
/**
|
||||
* @element umb-property-editor-ui-checkbox-list
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-checkbox-list')
|
||||
export class UmbPropertyEditorUICheckboxListElement extends UmbLitElement implements UmbPropertyEditorUiElement {
|
||||
export class UmbPropertyEditorUICheckboxListElement
|
||||
extends UmbFormControlMixin<Array<string> | string | undefined, typeof UmbLitElement, undefined>(
|
||||
UmbLitElement,
|
||||
undefined,
|
||||
)
|
||||
implements UmbPropertyEditorUiElement
|
||||
{
|
||||
#selection: Array<string> = [];
|
||||
|
||||
@property({ type: Array })
|
||||
public set value(value: Array<string> | string | undefined) {
|
||||
public override set value(value: Array<string> | string | undefined) {
|
||||
this.#selection = Array.isArray(value) ? value : value ? [value] : [];
|
||||
}
|
||||
public get value(): Array<string> | undefined {
|
||||
public override get value(): Array<string> | undefined {
|
||||
return this.#selection;
|
||||
}
|
||||
|
||||
@@ -60,9 +67,23 @@ export class UmbPropertyEditorUICheckboxListElement extends UmbLitElement implem
|
||||
@property({ type: Boolean, reflect: true })
|
||||
readonly = false;
|
||||
|
||||
/**
|
||||
* Sets the input to mandatory, meaning validation will fail if the value is empty.
|
||||
* @type {boolean}
|
||||
*/
|
||||
@property({ type: Boolean })
|
||||
mandatory?: boolean;
|
||||
|
||||
@property({ type: String })
|
||||
mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;
|
||||
|
||||
@state()
|
||||
private _list: Array<UmbCheckboxListItem> = [];
|
||||
|
||||
protected override firstUpdated() {
|
||||
this.addFormControlElement(this.shadowRoot!.querySelector('umb-input-checkbox-list')!);
|
||||
}
|
||||
|
||||
#onChange(event: CustomEvent & { target: UmbInputCheckboxListElement }) {
|
||||
this.value = event.target.selection;
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
@@ -72,9 +93,12 @@ export class UmbPropertyEditorUICheckboxListElement extends UmbLitElement implem
|
||||
return html`
|
||||
<umb-input-checkbox-list
|
||||
.list=${this._list}
|
||||
.required=${this.mandatory}
|
||||
.requiredMessage=${this.mandatoryMessage}
|
||||
.selection=${this.#selection}
|
||||
?readonly=${this.readonly}
|
||||
@change=${this.#onChange}></umb-input-checkbox-list>
|
||||
@change=${this.#onChange}>
|
||||
</umb-input-checkbox-list>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,15 @@ export const manifest: ManifestPropertyEditorSchema = {
|
||||
properties: [
|
||||
{
|
||||
alias: 'group',
|
||||
label: 'Define a tag group',
|
||||
label: 'Tag group',
|
||||
description: '',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.TextBox',
|
||||
},
|
||||
{
|
||||
alias: 'storageType',
|
||||
label: 'Storage Type',
|
||||
description: '',
|
||||
description:
|
||||
'Select whether to store the tags in cache as JSON (default) or CSV format. Notice that CSV does not support commas in the tag value.',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Select',
|
||||
config: [
|
||||
{
|
||||
|
||||
@@ -135,29 +135,21 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle
|
||||
|
||||
#setSortProperty(event: Event) {
|
||||
const target = event.target as UUIComboboxListElement;
|
||||
|
||||
if (!this._queryRequest.sort) this.#setSortDirection();
|
||||
|
||||
this.#updateQueryRequest({
|
||||
sort: { ...this._queryRequest.sort, propertyAlias: target.value as string },
|
||||
});
|
||||
this.#setSort(target.value as string, this._queryRequest.sort?.direction as SortOrder ?? this._defaultSortDirection);
|
||||
}
|
||||
|
||||
#setSortDirection() {
|
||||
if (!this._queryRequest.sort?.direction) {
|
||||
this.#updateQueryRequest({
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
sort: { ...this._queryRequest.sort, direction: this._defaultSortDirection },
|
||||
});
|
||||
return;
|
||||
const direction = this._queryRequest.sort?.direction
|
||||
? this._queryRequest.sort.direction === SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending
|
||||
: this._defaultSortDirection;
|
||||
this.#setSort(this._queryRequest.sort?.propertyAlias ?? "", direction);
|
||||
}
|
||||
|
||||
#setSort(propertyAlias: string, direction: SortOrder) {
|
||||
this.#updateQueryRequest({
|
||||
sort: {
|
||||
...this._queryRequest.sort,
|
||||
direction:
|
||||
this._queryRequest.sort?.direction === SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending,
|
||||
propertyAlias,
|
||||
direction
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@ export interface MetaTinyMcePlugin {
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Sets the default configuration for the TinyMCE editor. This configuration will be used when the editor is initialized.
|
||||
* @see [TinyMCE Configuration](https://www.tiny.cloud/docs/configure/) for more information.
|
||||
* @title Sets the default configuration for the TinyMCE editor.
|
||||
* @description This configuration will be used when the editor is initialized. See the [TinyMCE Configuration](https://www.tiny.cloud/docs/configure/) for more information.
|
||||
* @optional
|
||||
* @TJS-type object
|
||||
* @examples [
|
||||
* {
|
||||
* "plugins": "wordcount",
|
||||
|
||||
@@ -52,6 +52,10 @@ console.log('--- Copying TinyMCE i18n done ---');
|
||||
// Copy monaco-editor
|
||||
console.log('--- Copying monaco-editor ---');
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/editor/editor.worker.js', `${DIST_DIRECTORY}/monaco-editor/vs/editor/editor.worker.js`);
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/base', `${DIST_DIRECTORY}/monaco-editor/vs/base`, { recursive: true });
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/nls.js', `${DIST_DIRECTORY}/monaco-editor/vs/nls.js`, { recursive: true });
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/nls.messages.js', `${DIST_DIRECTORY}/monaco-editor/vs/nls.messages.js`, { recursive: true });
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/editor/common', `${DIST_DIRECTORY}/monaco-editor/vs/editor/common`, { recursive: true });
|
||||
cpSync('./node_modules/monaco-editor/esm/vs/language', `${DIST_DIRECTORY}/monaco-editor/vs/language`, { recursive: true });
|
||||
cpSync('./node_modules/monaco-editor/min/vs/base/browser/ui/codicons', `${DIST_DIRECTORY}/assets/fonts`, { recursive: true });
|
||||
console.log('--- Copying monaco-editor done ---');
|
||||
|
||||
@@ -35,7 +35,7 @@ export const plugins: PluginOption[] = [
|
||||
},
|
||||
{
|
||||
src: 'node_modules/monaco-editor/esm/**/*',
|
||||
dest: 'umbraco/backoffice/monaco-editor/esm',
|
||||
dest: 'umbraco/backoffice/monaco-editor/vs',
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -136,22 +136,6 @@
|
||||
],
|
||||
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
|
||||
"continueOnError": true
|
||||
},
|
||||
{
|
||||
"actionId": "3A7C4B45-1F5D-4A30-959A-51B88E82B5D2",
|
||||
"args": {
|
||||
"executable": "powershell",
|
||||
"args": "cd Client;npm install;npm run build;",
|
||||
"redirectStandardError": false,
|
||||
"redirectStandardOutput": false
|
||||
},
|
||||
"manualInstructions": [
|
||||
{
|
||||
"text": "From the 'Client' folder run 'npm install' and then 'npm run build'"
|
||||
}
|
||||
],
|
||||
"continueOnError": true,
|
||||
"description ": "Installs node modules"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
@@ -160,8 +144,7 @@
|
||||
{
|
||||
"condition": "(!IncludeExample)",
|
||||
"exclude": [
|
||||
"[Cc]lient/src/dashboards/**",
|
||||
"[Cc]lient/src/api/schemas.gen.ts"
|
||||
"[Cc]lient/src/dashboards/**"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"generate-client": "node scripts/generate-openapi.js https://localhost:44339/umbraco/swagger/umbracoextension/swagger.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hey-api/client-fetch": "^0.4.2",
|
||||
"@hey-api/openapi-ts": "^0.53.11",
|
||||
"@hey-api/client-fetch": "^0.8.3",
|
||||
"@hey-api/openapi-ts": "^0.64.10",
|
||||
"@umbraco-cms/backoffice": "^UMBRACO_VERSION_FROM_TEMPLATE",
|
||||
"chalk": "^5.3.0",
|
||||
"chalk": "^5.4.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.9"
|
||||
"typescript": "^5.8.2",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"id": "Umbraco.Extension",
|
||||
"name": "Umbraco.Extension",
|
||||
"version": "0.0.0",
|
||||
"allowPackageTelemetry": true,
|
||||
"allowTelemetry": true,
|
||||
"extensions": [
|
||||
{
|
||||
"name": "Umbraco ExtensionBundle",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fetch from 'node-fetch';
|
||||
import chalk from 'chalk';
|
||||
import { createClient } from '@hey-api/openapi-ts';
|
||||
import { createClient, defaultPlugins } from '@hey-api/openapi-ts';
|
||||
|
||||
// Start notifying user we are generating the TypeScript client
|
||||
console.log(chalk.green("Generating OpenAPI client..."));
|
||||
@@ -20,7 +20,7 @@ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
console.log("Ensure your Umbraco instance is running");
|
||||
console.log(`Fetching OpenAPI definition from ${chalk.yellow(swaggerUrl)}`);
|
||||
|
||||
fetch(swaggerUrl).then(response => {
|
||||
fetch(swaggerUrl).then(async (response) => {
|
||||
if (!response.ok) {
|
||||
console.error(chalk.red(`ERROR: OpenAPI spec returned with a non OK (200) response: ${response.status} ${response.statusText}`));
|
||||
console.error(`The URL to your Umbraco instance may be wrong or the instance is not running`);
|
||||
@@ -31,13 +31,21 @@ fetch(swaggerUrl).then(response => {
|
||||
console.log(`OpenAPI spec fetched successfully`);
|
||||
console.log(`Calling ${chalk.yellow('hey-api')} to generate TypeScript client`);
|
||||
|
||||
createClient({
|
||||
client: '@hey-api/client-fetch',
|
||||
await createClient({
|
||||
input: swaggerUrl,
|
||||
output: 'src/api',
|
||||
services: {
|
||||
asClass: true,
|
||||
plugins: [
|
||||
...defaultPlugins,
|
||||
'@hey-api/client-fetch',
|
||||
{
|
||||
name: '@hey-api/typescript',
|
||||
enums: 'typescript'
|
||||
},
|
||||
{
|
||||
name: '@hey-api/sdk',
|
||||
asClass: true
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
18
templates/UmbracoExtension/Client/src/api/client.gen.ts
Normal file
18
templates/UmbracoExtension/Client/src/api/client.gen.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type { ClientOptions } from './types.gen';
|
||||
import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch';
|
||||
|
||||
/**
|
||||
* The `createClientConfig()` function will be called on client initialization
|
||||
* and the returned object will become the client's initial configuration.
|
||||
*
|
||||
* You may want to initialize your client this way instead of calling
|
||||
* `setConfig()`. This is useful for example if you're using Next.js
|
||||
* to ensure your client always has the correct values.
|
||||
*/
|
||||
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
|
||||
|
||||
export const client = createClient(createConfig<ClientOptions>({
|
||||
baseUrl: 'https://localhost:44389'
|
||||
}));
|
||||
@@ -1,6 +1,3 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
//#if(IncludeExample)
|
||||
export * from './schemas.gen';
|
||||
//#endif
|
||||
export * from './services.gen';
|
||||
export * from './types.gen';
|
||||
export * from './sdk.gen';
|
||||
@@ -1,391 +0,0 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
export const DocumentGranularPermissionModelSchema = {
|
||||
required: ['context', 'key', 'permission'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
key: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
},
|
||||
context: {
|
||||
type: 'string',
|
||||
readOnly: true
|
||||
},
|
||||
permission: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const ReadOnlyUserGroupModelSchema = {
|
||||
required: ['alias', 'allowedLanguages', 'allowedSections', 'granularPermissions', 'hasAccessToAllLanguages', 'id', 'key', 'name', 'permissions'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
},
|
||||
name: {
|
||||
type: 'string'
|
||||
},
|
||||
icon: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
startContentId: {
|
||||
type: 'integer',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
startMediaId: {
|
||||
type: 'integer',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
alias: {
|
||||
type: 'string'
|
||||
},
|
||||
hasAccessToAllLanguages: {
|
||||
type: 'boolean'
|
||||
},
|
||||
allowedLanguages: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
}
|
||||
},
|
||||
permissions: {
|
||||
uniqueItems: true,
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
granularPermissions: {
|
||||
uniqueItems: true,
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
'$ref': '#/components/schemas/DocumentGranularPermissionModel'
|
||||
},
|
||||
{
|
||||
'$ref': '#/components/schemas/UnknownTypeGranularPermissionModel'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
allowedSections: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const UnknownTypeGranularPermissionModelSchema = {
|
||||
required: ['context', 'permission'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
context: {
|
||||
type: 'string'
|
||||
},
|
||||
permission: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const UserGroupModelSchema = {
|
||||
required: ['alias', 'allowedLanguages', 'allowedSections', 'createDate', 'granularPermissions', 'hasAccessToAllLanguages', 'hasIdentity', 'id', 'key', 'permissions', 'updateDate', 'userCount'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
},
|
||||
createDate: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
updateDate: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
deleteDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
hasIdentity: {
|
||||
type: 'boolean',
|
||||
readOnly: true
|
||||
},
|
||||
startMediaId: {
|
||||
type: 'integer',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
startContentId: {
|
||||
type: 'integer',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
icon: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
alias: {
|
||||
type: 'string'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
hasAccessToAllLanguages: {
|
||||
type: 'boolean'
|
||||
},
|
||||
permissions: {
|
||||
uniqueItems: true,
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
granularPermissions: {
|
||||
uniqueItems: true,
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
'$ref': '#/components/schemas/DocumentGranularPermissionModel'
|
||||
},
|
||||
{
|
||||
'$ref': '#/components/schemas/UnknownTypeGranularPermissionModel'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
allowedSections: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
userCount: {
|
||||
type: 'integer',
|
||||
format: 'int32',
|
||||
readOnly: true
|
||||
},
|
||||
allowedLanguages: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const UserKindModelSchema = {
|
||||
enum: ['Default', 'Api'],
|
||||
type: 'string'
|
||||
} as const;
|
||||
|
||||
export const UserModelSchema = {
|
||||
required: ['allowedSections', 'createDate', 'email', 'failedPasswordAttempts', 'groups', 'hasIdentity', 'id', 'isApproved', 'isLockedOut', 'key', 'kind', 'profileData', 'sessionTimeout', 'updateDate', 'username', 'userState'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
key: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
},
|
||||
createDate: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
updateDate: {
|
||||
type: 'string',
|
||||
format: 'date-time'
|
||||
},
|
||||
deleteDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
hasIdentity: {
|
||||
type: 'boolean',
|
||||
readOnly: true
|
||||
},
|
||||
emailConfirmedDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
invitedDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
username: {
|
||||
type: 'string'
|
||||
},
|
||||
email: {
|
||||
type: 'string'
|
||||
},
|
||||
rawPasswordValue: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
passwordConfiguration: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
isApproved: {
|
||||
type: 'boolean'
|
||||
},
|
||||
isLockedOut: {
|
||||
type: 'boolean'
|
||||
},
|
||||
lastLoginDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
lastPasswordChangeDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
lastLockoutDate: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
nullable: true
|
||||
},
|
||||
failedPasswordAttempts: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
comments: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
userState: {
|
||||
'$ref': '#/components/schemas/UserStateModel'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
allowedSections: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
profileData: {
|
||||
oneOf: [
|
||||
{
|
||||
'$ref': '#/components/schemas/UserModel'
|
||||
},
|
||||
{
|
||||
'$ref': '#/components/schemas/UserProfileModel'
|
||||
}
|
||||
],
|
||||
readOnly: true
|
||||
},
|
||||
securityStamp: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
avatar: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
sessionTimeout: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
startContentIds: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
nullable: true
|
||||
},
|
||||
startMediaIds: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
nullable: true
|
||||
},
|
||||
language: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
},
|
||||
kind: {
|
||||
'$ref': '#/components/schemas/UserKindModel'
|
||||
},
|
||||
groups: {
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [
|
||||
{
|
||||
'$ref': '#/components/schemas/ReadOnlyUserGroupModel'
|
||||
},
|
||||
{
|
||||
'$ref': '#/components/schemas/UserGroupModel'
|
||||
}
|
||||
]
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const UserProfileModelSchema = {
|
||||
required: ['id'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer',
|
||||
format: 'int32'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
nullable: true
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
|
||||
export const UserStateModelSchema = {
|
||||
enum: ['Active', 'Disabled', 'LockedOut', 'Invited', 'Inactive', 'All'],
|
||||
type: 'string'
|
||||
} as const;
|
||||
78
templates/UmbracoExtension/Client/src/api/sdk.gen.ts
Normal file
78
templates/UmbracoExtension/Client/src/api/sdk.gen.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';
|
||||
//#if(IncludeExample)
|
||||
import type { PingData, PingResponse, WhatsMyNameData, WhatsMyNameResponse, WhatsTheTimeMrWolfData, WhatsTheTimeMrWolfResponse, WhoAmIData, WhoAmIResponse } from './types.gen';
|
||||
//#else
|
||||
import type { PingData, PingResponse } from './types.gen';
|
||||
//#endif
|
||||
import { client as _heyApiClient } from './client.gen';
|
||||
|
||||
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
|
||||
/**
|
||||
* You can provide a client instance returned by `createClient()` instead of
|
||||
* individual options. This might be also useful if you want to implement a
|
||||
* custom client.
|
||||
*/
|
||||
client?: Client;
|
||||
/**
|
||||
* You can pass arbitrary values through the `meta` object. This can be
|
||||
* used to access values that aren't defined as part of the SDK function.
|
||||
*/
|
||||
meta?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export class UmbracoExtensionService {
|
||||
public static ping<ThrowOnError extends boolean = false>(options?: Options<PingData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<PingResponse, unknown, ThrowOnError>({
|
||||
security: [
|
||||
{
|
||||
scheme: 'bearer',
|
||||
type: 'http'
|
||||
}
|
||||
],
|
||||
url: '/umbraco/umbracoextension/api/v1/ping',
|
||||
...options
|
||||
});
|
||||
}
|
||||
//#if(IncludeExample)
|
||||
public static whatsMyName<ThrowOnError extends boolean = false>(options?: Options<WhatsMyNameData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<WhatsMyNameResponse, unknown, ThrowOnError>({
|
||||
security: [
|
||||
{
|
||||
scheme: 'bearer',
|
||||
type: 'http'
|
||||
}
|
||||
],
|
||||
url: '/umbraco/umbracoextension/api/v1/whatsMyName',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
public static whatsTheTimeMrWolf<ThrowOnError extends boolean = false>(options?: Options<WhatsTheTimeMrWolfData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<WhatsTheTimeMrWolfResponse, unknown, ThrowOnError>({
|
||||
security: [
|
||||
{
|
||||
scheme: 'bearer',
|
||||
type: 'http'
|
||||
}
|
||||
],
|
||||
url: '/umbraco/umbracoextension/api/v1/whatsTheTimeMrWolf',
|
||||
...options
|
||||
});
|
||||
}
|
||||
|
||||
public static whoAmI<ThrowOnError extends boolean = false>(options?: Options<WhoAmIData, ThrowOnError>) {
|
||||
return (options?.client ?? _heyApiClient).get<WhoAmIResponse, unknown, ThrowOnError>({
|
||||
security: [
|
||||
{
|
||||
scheme: 'bearer',
|
||||
type: 'http'
|
||||
}
|
||||
],
|
||||
url: '/umbraco/umbracoextension/api/v1/whoAmI',
|
||||
...options
|
||||
});
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import { createClient, createConfig, type Options } from '@hey-api/client-fetch';
|
||||
//#if(IncludeExample)
|
||||
import type { PingError, PingResponse, WhatsMyNameError, WhatsMyNameResponse, WhatsTheTimeMrWolfError, WhatsTheTimeMrWolfResponse, WhoAmIError, WhoAmIResponse } from './types.gen';
|
||||
//#else
|
||||
import type { PingError, PingResponse } from './types.gen';
|
||||
//#endif
|
||||
|
||||
export const client = createClient(createConfig());
|
||||
|
||||
export class UmbracoExtensionService {
|
||||
public static ping<ThrowOnError extends boolean = false>(options?: Options<unknown, ThrowOnError>) {
|
||||
return (options?.client ?? client).get<PingResponse, PingError, ThrowOnError>({
|
||||
...options,
|
||||
url: '/umbraco/umbracoextension/api/v1/ping'
|
||||
});
|
||||
}
|
||||
//#if(IncludeExample)
|
||||
public static whatsMyName<ThrowOnError extends boolean = false>(options?: Options<unknown, ThrowOnError>) {
|
||||
return (options?.client ?? client).get<WhatsMyNameResponse, WhatsMyNameError, ThrowOnError>({
|
||||
...options,
|
||||
url: '/umbraco/umbracoextension/api/v1/whatsMyName'
|
||||
});
|
||||
}
|
||||
|
||||
public static whatsTheTimeMrWolf<ThrowOnError extends boolean = false>(options?: Options<unknown, ThrowOnError>) {
|
||||
return (options?.client ?? client).get<WhatsTheTimeMrWolfResponse, WhatsTheTimeMrWolfError, ThrowOnError>({
|
||||
...options,
|
||||
url: '/umbraco/umbracoextension/api/v1/whatsTheTimeMrWolf'
|
||||
});
|
||||
}
|
||||
|
||||
public static whoAmI<ThrowOnError extends boolean = false>(options?: Options<unknown, ThrowOnError>) {
|
||||
return (options?.client ?? client).get<WhoAmIResponse, WhoAmIError, ThrowOnError>({
|
||||
...options,
|
||||
url: '/umbraco/umbracoextension/api/v1/whoAmI'
|
||||
});
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
@@ -10,15 +10,15 @@ export type ReadOnlyUserGroupModel = {
|
||||
id: number;
|
||||
key: string;
|
||||
name: string;
|
||||
icon?: (string) | null;
|
||||
startContentId?: (number) | null;
|
||||
startMediaId?: (number) | null;
|
||||
icon?: string | null;
|
||||
startContentId?: number | null;
|
||||
startMediaId?: number | null;
|
||||
alias: string;
|
||||
hasAccessToAllLanguages: boolean;
|
||||
allowedLanguages: Array<(number)>;
|
||||
permissions: Array<(string)>;
|
||||
granularPermissions: Array<(DocumentGranularPermissionModel | UnknownTypeGranularPermissionModel)>;
|
||||
allowedSections: Array<(string)>;
|
||||
allowedLanguages: Array<number>;
|
||||
permissions: Array<string>;
|
||||
granularPermissions: Array<DocumentGranularPermissionModel | UnknownTypeGranularPermissionModel>;
|
||||
allowedSections: Array<string>;
|
||||
};
|
||||
|
||||
export type UnknownTypeGranularPermissionModel = {
|
||||
@@ -31,77 +31,166 @@ export type UserGroupModel = {
|
||||
key: string;
|
||||
createDate: string;
|
||||
updateDate: string;
|
||||
deleteDate?: (string) | null;
|
||||
deleteDate?: string | null;
|
||||
readonly hasIdentity: boolean;
|
||||
startMediaId?: (number) | null;
|
||||
startContentId?: (number) | null;
|
||||
icon?: (string) | null;
|
||||
startMediaId?: number | null;
|
||||
startContentId?: number | null;
|
||||
icon?: string | null;
|
||||
alias: string;
|
||||
name?: (string) | null;
|
||||
name?: string | null;
|
||||
hasAccessToAllLanguages: boolean;
|
||||
permissions: Array<(string)>;
|
||||
granularPermissions: Array<(DocumentGranularPermissionModel | UnknownTypeGranularPermissionModel)>;
|
||||
readonly allowedSections: Array<(string)>;
|
||||
permissions: Array<string>;
|
||||
granularPermissions: Array<DocumentGranularPermissionModel | UnknownTypeGranularPermissionModel>;
|
||||
readonly allowedSections: Array<string>;
|
||||
readonly userCount: number;
|
||||
readonly allowedLanguages: Array<(number)>;
|
||||
readonly allowedLanguages: Array<number>;
|
||||
};
|
||||
|
||||
export type UserKindModel = 'Default' | 'Api';
|
||||
export enum UserKindModel {
|
||||
DEFAULT = 'Default',
|
||||
API = 'Api'
|
||||
}
|
||||
|
||||
export type UserModel = {
|
||||
id: number;
|
||||
key: string;
|
||||
createDate: string;
|
||||
updateDate: string;
|
||||
deleteDate?: (string) | null;
|
||||
deleteDate?: string | null;
|
||||
readonly hasIdentity: boolean;
|
||||
emailConfirmedDate?: (string) | null;
|
||||
invitedDate?: (string) | null;
|
||||
emailConfirmedDate?: string | null;
|
||||
invitedDate?: string | null;
|
||||
username: string;
|
||||
email: string;
|
||||
rawPasswordValue?: (string) | null;
|
||||
passwordConfiguration?: (string) | null;
|
||||
rawPasswordValue?: string | null;
|
||||
passwordConfiguration?: string | null;
|
||||
isApproved: boolean;
|
||||
isLockedOut: boolean;
|
||||
lastLoginDate?: (string) | null;
|
||||
lastPasswordChangeDate?: (string) | null;
|
||||
lastLockoutDate?: (string) | null;
|
||||
lastLoginDate?: string | null;
|
||||
lastPasswordChangeDate?: string | null;
|
||||
lastLockoutDate?: string | null;
|
||||
failedPasswordAttempts: number;
|
||||
comments?: (string) | null;
|
||||
comments?: string | null;
|
||||
userState: UserStateModel;
|
||||
name?: (string) | null;
|
||||
readonly allowedSections: Array<(string)>;
|
||||
readonly profileData: (UserModel | UserProfileModel);
|
||||
securityStamp?: (string) | null;
|
||||
avatar?: (string) | null;
|
||||
name?: string | null;
|
||||
readonly allowedSections: Array<string>;
|
||||
profileData: UserModel | UserProfileModel;
|
||||
securityStamp?: string | null;
|
||||
avatar?: string | null;
|
||||
sessionTimeout: number;
|
||||
startContentIds?: Array<(number)> | null;
|
||||
startMediaIds?: Array<(number)> | null;
|
||||
language?: (string) | null;
|
||||
startContentIds?: Array<number> | null;
|
||||
startMediaIds?: Array<number> | null;
|
||||
language?: string | null;
|
||||
kind: UserKindModel;
|
||||
readonly groups: Array<(ReadOnlyUserGroupModel | UserGroupModel)>;
|
||||
readonly groups: Array<ReadOnlyUserGroupModel | UserGroupModel>;
|
||||
};
|
||||
|
||||
export type UserProfileModel = {
|
||||
id: number;
|
||||
name?: (string) | null;
|
||||
name?: string | null;
|
||||
};
|
||||
|
||||
export type UserStateModel = 'Active' | 'Disabled' | 'LockedOut' | 'Invited' | 'Inactive' | 'All';
|
||||
export enum UserStateModel {
|
||||
ACTIVE = 'Active',
|
||||
DISABLED = 'Disabled',
|
||||
LOCKED_OUT = 'LockedOut',
|
||||
INVITED = 'Invited',
|
||||
INACTIVE = 'Inactive',
|
||||
ALL = 'All'
|
||||
}
|
||||
//#endif
|
||||
export type PingResponse = (string);
|
||||
export type PingData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/umbraco/hackclient/api/v1/ping';
|
||||
};
|
||||
|
||||
export type PingError = (unknown);
|
||||
export type PingErrors = {
|
||||
/**
|
||||
* The resource is protected and requires an authentication token
|
||||
*/
|
||||
401: unknown;
|
||||
};
|
||||
|
||||
export type PingResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: string;
|
||||
};
|
||||
|
||||
export type PingResponse = PingResponses[keyof PingResponses];
|
||||
//#if(IncludeExample)
|
||||
export type WhatsMyNameResponse = (string);
|
||||
export type WhatsMyNameData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/umbraco/hackclient/api/v1/whatsMyName';
|
||||
};
|
||||
|
||||
export type WhatsMyNameError = (unknown);
|
||||
export type WhatsMyNameErrors = {
|
||||
/**
|
||||
* The resource is protected and requires an authentication token
|
||||
*/
|
||||
401: unknown;
|
||||
};
|
||||
|
||||
export type WhatsTheTimeMrWolfResponse = (string);
|
||||
export type WhatsMyNameResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: string;
|
||||
};
|
||||
|
||||
export type WhatsTheTimeMrWolfError = (unknown);
|
||||
export type WhatsMyNameResponse = WhatsMyNameResponses[keyof WhatsMyNameResponses];
|
||||
|
||||
export type WhoAmIResponse = ((UserModel));
|
||||
export type WhatsTheTimeMrWolfData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/umbraco/hackclient/api/v1/whatsTheTimeMrWolf';
|
||||
};
|
||||
|
||||
export type WhoAmIError = (unknown);
|
||||
export type WhatsTheTimeMrWolfErrors = {
|
||||
/**
|
||||
* The resource is protected and requires an authentication token
|
||||
*/
|
||||
401: unknown;
|
||||
};
|
||||
|
||||
export type WhatsTheTimeMrWolfResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: string;
|
||||
};
|
||||
|
||||
export type WhatsTheTimeMrWolfResponse = WhatsTheTimeMrWolfResponses[keyof WhatsTheTimeMrWolfResponses];
|
||||
|
||||
export type WhoAmIData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: '/umbraco/hackclient/api/v1/whoAmI';
|
||||
};
|
||||
|
||||
export type WhoAmIErrors = {
|
||||
/**
|
||||
* The resource is protected and requires an authentication token
|
||||
*/
|
||||
401: unknown;
|
||||
};
|
||||
|
||||
export type WhoAmIResponses = {
|
||||
/**
|
||||
* OK
|
||||
*/
|
||||
200: UserModel;
|
||||
};
|
||||
|
||||
export type WhoAmIResponse = WhoAmIResponses[keyof WhoAmIResponses];
|
||||
//#endif
|
||||
export type ClientOptions = {
|
||||
baseUrl: 'https://localhost:44389' | (string & {});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { manifests as entrypoints } from './entrypoints/manifest';
|
||||
import { manifests as entrypoints } from "./entrypoints/manifest.js";
|
||||
//#if IncludeExample
|
||||
import { manifests as dashboards } from './dashboards/manifest';
|
||||
import { manifests as dashboards } from "./dashboards/manifest.js";
|
||||
//#endif
|
||||
|
||||
// Job of the bundle is to collate all the manifests from different parts of the extension and load other manifests
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { LitElement, css, html, customElement, state } from "@umbraco-cms/backoffice/external/lit";
|
||||
import {
|
||||
LitElement,
|
||||
css,
|
||||
html,
|
||||
customElement,
|
||||
state,
|
||||
} from "@umbraco-cms/backoffice/external/lit";
|
||||
import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api";
|
||||
import { UmbracoExtensionService, UserModel } from "../api";
|
||||
import { UUIButtonElement } from "@umbraco-cms/backoffice/external/uui";
|
||||
import { UMB_NOTIFICATION_CONTEXT, UmbNotificationContext } from "@umbraco-cms/backoffice/notification";
|
||||
import { UMB_CURRENT_USER_CONTEXT, UmbCurrentUserModel } from "@umbraco-cms/backoffice/current-user";
|
||||
import {
|
||||
UMB_NOTIFICATION_CONTEXT,
|
||||
UmbNotificationContext,
|
||||
} from "@umbraco-cms/backoffice/notification";
|
||||
import {
|
||||
UMB_CURRENT_USER_CONTEXT,
|
||||
UmbCurrentUserModel,
|
||||
} from "@umbraco-cms/backoffice/current-user";
|
||||
import { UmbracoExtensionService, UserModel } from "../api/index.js";
|
||||
|
||||
@customElement('example-dashboard')
|
||||
@customElement("example-dashboard")
|
||||
export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
|
||||
@state()
|
||||
private _yourName: string | undefined = "Press the button!";
|
||||
|
||||
@@ -28,7 +39,6 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_CONTEXT, (currentUserContext) => {
|
||||
|
||||
// When we have the current user context
|
||||
// We can observe properties from it, such as the current user or perhaps just individual properties
|
||||
// When the currentUser object changes we will get notified and can reset the @state properrty
|
||||
@@ -62,10 +72,10 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
data: {
|
||||
headline: `You are ${this._serverUserData?.name}`,
|
||||
message: `Your email is ${this._serverUserData?.email}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#onClickWhatsTheTimeMrWolf = async (ev: Event) => {
|
||||
const buttonElement = ev.target as UUIButtonElement;
|
||||
@@ -84,7 +94,7 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
this._timeFromMrWolf = new Date(data);
|
||||
buttonElement.state = "success";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#onClickWhatsMyName = async (ev: Event) => {
|
||||
const buttonElement = ev.target as UUIButtonElement;
|
||||
@@ -100,36 +110,64 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
|
||||
this._yourName = data;
|
||||
buttonElement.state = "success";
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-box headline="Who am I?">
|
||||
<div slot="header">[Server]</div>
|
||||
<h2><uui-icon name="icon-user"></uui-icon>${this._serverUserData?.email ? this._serverUserData.email : 'Press the button!'}</h2>
|
||||
<h2>
|
||||
<uui-icon name="icon-user"></uui-icon>${this._serverUserData?.email
|
||||
? this._serverUserData.email
|
||||
: "Press the button!"}
|
||||
</h2>
|
||||
<ul>
|
||||
${this._serverUserData?.groups.map(group => html`<li>${group.name}</li>`)}
|
||||
${this._serverUserData?.groups.map(
|
||||
(group) => html`<li>${group.name}</li>`
|
||||
)}
|
||||
</ul>
|
||||
<uui-button color="default" look="primary" @click="${this.#onClickWhoAmI}">
|
||||
<uui-button
|
||||
color="default"
|
||||
look="primary"
|
||||
@click="${this.#onClickWhoAmI}"
|
||||
>
|
||||
Who am I?
|
||||
</uui-button>
|
||||
<p>This endpoint gets your current user from the server and displays your email and list of user groups.
|
||||
It also displays a Notification with your details.</p>
|
||||
<p>
|
||||
This endpoint gets your current user from the server and displays your
|
||||
email and list of user groups. It also displays a Notification with
|
||||
your details.
|
||||
</p>
|
||||
</uui-box>
|
||||
|
||||
<uui-box headline="What's my Name?">
|
||||
<div slot="header">[Server]</div>
|
||||
<h2><uui-icon name="icon-user"></uui-icon> ${this._yourName}</h2>
|
||||
<uui-button color="default" look="primary" @click="${this.#onClickWhatsMyName}">
|
||||
<uui-button
|
||||
color="default"
|
||||
look="primary"
|
||||
@click="${this.#onClickWhatsMyName}"
|
||||
>
|
||||
Whats my name?
|
||||
</uui-button>
|
||||
<p>This endpoint has a forced delay to show the button 'waiting' state for a few seconds before completing the request.</p>
|
||||
<p>
|
||||
This endpoint has a forced delay to show the button 'waiting' state
|
||||
for a few seconds before completing the request.
|
||||
</p>
|
||||
</uui-box>
|
||||
|
||||
<uui-box headline="What's the Time?">
|
||||
<div slot="header">[Server]</div>
|
||||
<h2><uui-icon name="icon-alarm-clock"></uui-icon> ${this._timeFromMrWolf ? this._timeFromMrWolf.toLocaleString() : 'Press the button!'}</h2>
|
||||
<uui-button color="default" look="primary" @click="${this.#onClickWhatsTheTimeMrWolf}">
|
||||
<h2>
|
||||
<uui-icon name="icon-alarm-clock"></uui-icon> ${this._timeFromMrWolf
|
||||
? this._timeFromMrWolf.toLocaleString()
|
||||
: "Press the button!"}
|
||||
</h2>
|
||||
<uui-button
|
||||
color="default"
|
||||
look="primary"
|
||||
@click="${this.#onClickWhatsTheTimeMrWolf}"
|
||||
>
|
||||
Whats the time Mr Wolf?
|
||||
</uui-button>
|
||||
<p>This endpoint gets the current date and time from the server.</p>
|
||||
@@ -138,8 +176,13 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
<uui-box headline="Who am I?" class="wide">
|
||||
<div slot="header">[Context]</div>
|
||||
<p>Current user email: <b>${this._contextCurrentUser?.email}</b></p>
|
||||
<p>This is the JSON object available by consuming the 'UMB_CURRENT_USER_CONTEXT' context:</p>
|
||||
<umb-code-block language="json" copy>${JSON.stringify(this._contextCurrentUser, null, 2)}</umb-code-block>
|
||||
<p>
|
||||
This is the JSON object available by consuming the
|
||||
'UMB_CURRENT_USER_CONTEXT' context:
|
||||
</p>
|
||||
<umb-code-block language="json" copy
|
||||
>${JSON.stringify(this._contextCurrentUser, null, 2)}</umb-code-block
|
||||
>
|
||||
</uui-box>
|
||||
`;
|
||||
}
|
||||
@@ -164,13 +207,14 @@ export class ExampleDashboardElement extends UmbElementMixin(LitElement) {
|
||||
.wide {
|
||||
grid-column: span 3;
|
||||
}
|
||||
`];
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default ExampleDashboardElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'example-dashboard': ExampleDashboardElement;
|
||||
"example-dashboard": ExampleDashboardElement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@ export const manifests: Array<UmbExtensionManifest> = [
|
||||
{
|
||||
name: "Umbraco ExtensionDashboard",
|
||||
alias: "Umbraco.Extension.Dashboard",
|
||||
type: 'dashboard',
|
||||
js: () => import("./dashboard.element"),
|
||||
type: "dashboard",
|
||||
js: () => import("./dashboard.element.js"),
|
||||
meta: {
|
||||
label: "Example Dashboard",
|
||||
pathname: "example-dashboard"
|
||||
pathname: "example-dashboard",
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
alias: 'Umb.Condition.SectionAlias',
|
||||
match: 'Umb.Section.Content',
|
||||
}
|
||||
alias: "Umb.Condition.SectionAlias",
|
||||
match: "Umb.Section.Content",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,38 +1,31 @@
|
||||
import { UmbEntryPointOnInit, UmbEntryPointOnUnload } from '@umbraco-cms/backoffice/extension-api';
|
||||
import {
|
||||
UmbEntryPointOnInit,
|
||||
UmbEntryPointOnUnload,
|
||||
} from "@umbraco-cms/backoffice/extension-api";
|
||||
//#if IncludeExample
|
||||
import { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
|
||||
import { client } from '../api';
|
||||
import { UMB_AUTH_CONTEXT } from "@umbraco-cms/backoffice/auth";
|
||||
import { client } from "../api/client.gen.js";
|
||||
//#endif
|
||||
|
||||
// load up the manifests here
|
||||
export const onInit: UmbEntryPointOnInit = (_host, _extensionRegistry) => {
|
||||
|
||||
console.log('Hello from my extension 🎉');
|
||||
console.log("Hello from my extension 🎉");
|
||||
//#if IncludeExample
|
||||
// Will use only to add in Open API config with generated TS OpenAPI HTTPS Client
|
||||
// Do the OAuth token handshake stuff
|
||||
_host.consumeContext(UMB_AUTH_CONTEXT, async (authContext) => {
|
||||
|
||||
// Get the token info from Umbraco
|
||||
const config = authContext.getOpenApiConfiguration();
|
||||
|
||||
client.setConfig({
|
||||
auth: config.token,
|
||||
baseUrl: config.base,
|
||||
credentials: config.credentials
|
||||
});
|
||||
|
||||
// For every request being made, add the token to the headers
|
||||
// Can't use the setConfig approach above as its set only once and
|
||||
// tokens expire and get refreshed
|
||||
client.interceptors.request.use(async (request, _options) => {
|
||||
const token = await config.token();
|
||||
request.headers.set('Authorization', `Bearer ${token}`);
|
||||
return request;
|
||||
credentials: config.credentials,
|
||||
});
|
||||
});
|
||||
//#endif
|
||||
};
|
||||
|
||||
export const onUnload: UmbEntryPointOnUnload = (_host, _extensionRegistry) => {
|
||||
console.log('Goodbye from my extension 👋');
|
||||
console.log("Goodbye from my extension 👋");
|
||||
};
|
||||
|
||||
@@ -3,6 +3,6 @@ export const manifests: Array<UmbExtensionManifest> = [
|
||||
name: "Umbraco ExtensionEntrypoint",
|
||||
alias: "Umbraco.Extension.Entrypoint",
|
||||
type: "backofficeEntryPoint",
|
||||
js: () => import("./entrypoint"),
|
||||
}
|
||||
js: () => import("./entrypoint.js"),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -13,5 +13,5 @@ export default defineConfig({
|
||||
rollupOptions: {
|
||||
external: [/^@umbraco/],
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClientAssetsInputs Include="Client\**" Exclude="$(DefaultItemExcludes)" />
|
||||
|
||||
<!-- Dont include the client folder as part of packaging nuget build -->
|
||||
<Content Remove="Client\**" />
|
||||
|
||||
@@ -33,4 +35,23 @@
|
||||
<None Include="Client\public\umbraco-package.json" Pack="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Restore and build Client files -->
|
||||
<Target Name="RestoreClient" Inputs="Client\package.json;Client\package-lock.json" Outputs="Client\node_modules\.package-lock.json">
|
||||
<Message Importance="high" Text="Restoring Client NPM packages..." />
|
||||
<Exec Command="npm i" WorkingDirectory="Client" />
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildClient" BeforeTargets="AssignTargetPaths" DependsOnTargets="RestoreClient" Inputs="@(ClientAssetsInputs)" Outputs="$(IntermediateOutputPath)client.complete.txt">
|
||||
<Message Importance="high" Text="Executing Client NPM build script..." />
|
||||
<Exec Command="npm run build" WorkingDirectory="Client" />
|
||||
<ItemGroup>
|
||||
<_ClientAssetsBuildOutput Include="wwwroot\App_Plugins\**" />
|
||||
</ItemGroup>
|
||||
<WriteLinesToFile File="$(IntermediateOutputPath)client.complete.txt" Lines="@(_ClientAssetsBuildOutput)" Overwrite="true" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@umbraco/json-models-builders": "^2.0.29",
|
||||
"@umbraco/playwright-testhelpers": "^15.0.33",
|
||||
"@umbraco/playwright-testhelpers": "^15.0.34",
|
||||
"camelize": "^1.0.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"node-fetch": "^2.6.7"
|
||||
@@ -67,9 +67,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@umbraco/playwright-testhelpers": {
|
||||
"version": "15.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-15.0.33.tgz",
|
||||
"integrity": "sha512-EboW4KNFN5wG4UR8tsLWhjpQVZY0lkVNDbNFu9iohFE2bSfrV2CETcWAthVx8IwJja4nP3dOdwwMKb39/MUNdw==",
|
||||
"version": "15.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-15.0.34.tgz",
|
||||
"integrity": "sha512-dEWjiUCWdxBpvDnCoShqRZ5xEfNEo02BBgNIKqDAUDEBht/lAM/pDaUgzu2sUbb7D8AbkrrIxPiNn69XakoNSg==",
|
||||
"dependencies": {
|
||||
"@umbraco/json-models-builders": "2.0.30",
|
||||
"node-fetch": "^2.6.7"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@umbraco/json-models-builders": "^2.0.29",
|
||||
"@umbraco/playwright-testhelpers": "^15.0.33",
|
||||
"@umbraco/playwright-testhelpers": "^15.0.34",
|
||||
"camelize": "^1.0.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"node-fetch": "^2.6.7"
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import {expect} from '@playwright/test';
|
||||
import {AliasHelper, ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers';
|
||||
|
||||
// Document Type
|
||||
const documentTypeName = 'TestDocumentTypeForContent';
|
||||
let documentTypeId = '';
|
||||
|
||||
// Content
|
||||
const contentName = 'TestContent';
|
||||
|
||||
// Element Types
|
||||
const firstElementTypeName = 'FirstBlockGridElement';
|
||||
let firstElementTypeId = null;
|
||||
const secondElementTypeName = 'SecondBlockGridElement';
|
||||
|
||||
// Block Grid Data Type
|
||||
const blockGridDataTypeName = 'BlockGridTester';
|
||||
let blockGridDataTypeId = null;
|
||||
const firstAreaName = 'FirstArea';
|
||||
const areaCreateLabel = 'CreateLabel';
|
||||
const toAllowInAreas = true;
|
||||
|
||||
test.beforeEach(async ({umbracoApi}) => {
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
|
||||
await umbracoApi.documentType.ensureNameNotExists(firstElementTypeName);
|
||||
await umbracoApi.documentType.ensureNameNotExists(secondElementTypeName);
|
||||
await umbracoApi.document.ensureNameNotExists(contentName);
|
||||
await umbracoApi.dataType.ensureNameNotExists(blockGridDataTypeName);
|
||||
});
|
||||
|
||||
test.afterEach(async ({umbracoApi}) => {
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
|
||||
await umbracoApi.documentType.ensureNameNotExists(firstElementTypeName);
|
||||
await umbracoApi.documentType.ensureNameNotExists(secondElementTypeName);
|
||||
await umbracoApi.document.ensureNameNotExists(contentName);
|
||||
await umbracoApi.dataType.ensureNameNotExists(blockGridDataTypeName);
|
||||
});
|
||||
|
||||
test('can create content with a block grid with an empty block in a area', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithAllowInAreas(blockGridDataTypeName, firstElementTypeId, firstAreaName, toAllowInAreas, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickLinkWithName(areaCreateLabel);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
await umbracoUi.reloadPage();
|
||||
await umbracoUi.content.doesBlockContainBlockInAreaWithName(firstElementTypeName, firstAreaName, firstElementTypeName);
|
||||
await umbracoUi.content.doesBlockContainBlockCountInArea(firstElementTypeName, firstAreaName, 1);
|
||||
});
|
||||
|
||||
test('can create content with a block grid with two empty blocks in a area', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithAllowInAreas(blockGridDataTypeName, firstElementTypeId, firstAreaName, toAllowInAreas, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickLinkWithName(areaCreateLabel);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(firstElementTypeName);
|
||||
await umbracoUi.content.addBlockToAreasWithExistingBlock(firstElementTypeName, firstAreaName, 0, 0);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
await umbracoUi.reloadPage();
|
||||
await umbracoUi.content.doesBlockContainCountOfBlockInArea(firstElementTypeName, firstAreaName, firstElementTypeName, 2);
|
||||
|
||||
// Checks if the block grid contains the blocks through the API
|
||||
const parentBlockKey = await umbracoUi.content.getBlockAtRootDataElementKey(firstElementTypeName, 0);
|
||||
const areaKey = await umbracoUi.content.getBlockAreaKeyFromParentBlockDataElementKey(parentBlockKey, 0);
|
||||
const firstBlockInAreaKey = await umbracoUi.content.getBlockDataElementKeyInArea(firstElementTypeName, firstAreaName, firstElementTypeName, 0, 0);
|
||||
const secondBlockInAreaKey = await umbracoUi.content.getBlockDataElementKeyInArea(firstElementTypeName, firstAreaName, firstElementTypeName, 0, 1);
|
||||
expect(await umbracoApi.document.doesBlockGridContainBlocksWithDataElementKeyInAreaWithKey(contentName, AliasHelper.toAlias(blockGridDataTypeName), parentBlockKey, areaKey, [firstBlockInAreaKey, secondBlockInAreaKey])).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can create content with block grid area with a create label', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
const createLabel = 'ThisIsACreateLabel';
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithACreateLabel(blockGridDataTypeName, firstElementTypeId, createLabel, firstAreaName);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
await umbracoUi.content.doesBlockGridBlockWithAreaContainCreateLabel(firstElementTypeName, createLabel);
|
||||
});
|
||||
|
||||
test('can create content with block grid area with column span', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
const columnSpan = 2;
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithColumnSpanAndRowSpan(blockGridDataTypeName, firstElementTypeId, columnSpan, 1, firstAreaName, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
await umbracoUi.content.doesBlockAreaContainColumnSpan(firstElementTypeName, firstAreaName, columnSpan, 0);
|
||||
});
|
||||
|
||||
test('can create content with block grid area with row span', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
const rowSpan = 4;
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithColumnSpanAndRowSpan(blockGridDataTypeName, firstElementTypeId, 12, rowSpan, firstAreaName, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
await umbracoUi.content.doesBlockAreaContainRowSpan(firstElementTypeName, firstAreaName, rowSpan, 0);
|
||||
});
|
||||
|
||||
// Remove fixme when this issue is fixed https://github.com/umbraco/Umbraco-CMS/issues/18639
|
||||
test.fixme('can create content with block grid area with min allowed', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
const secondElementTypeId = await umbracoApi.documentType.createEmptyElementType(secondElementTypeName);
|
||||
const minAllowed = 2;
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithMinAndMaxAllowed(blockGridDataTypeName, firstElementTypeId, secondElementTypeId, minAllowed, 10, firstAreaName, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickLinkWithName(areaCreateLabel);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(secondElementTypeName);
|
||||
await umbracoUi.content.isTextWithExactNameVisible('Minimum 2 entries, requires 1 more.');
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.documentCouldNotBePublished);
|
||||
await umbracoUi.content.clickInlineAddToAreaButton(firstElementTypeName, firstAreaName, 0, 1);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(secondElementTypeName);
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
|
||||
// Clean
|
||||
await umbracoApi.documentType.ensureNameNotExists(secondElementTypeName);
|
||||
});
|
||||
|
||||
// Remove fixme when this issue is fixed https://github.com/umbraco/Umbraco-CMS/issues/18639
|
||||
test.fixme('can create content with block grid area with max allowed', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
firstElementTypeId = await umbracoApi.documentType.createEmptyElementType(firstElementTypeName);
|
||||
const secondElementTypeId = await umbracoApi.documentType.createEmptyElementType(secondElementTypeName);
|
||||
const maxAllowed = 0;
|
||||
blockGridDataTypeId = await umbracoApi.dataType.createBlockGridWithAnAreaInABlockWithMinAndMaxAllowed(blockGridDataTypeName, firstElementTypeId, secondElementTypeId, 0, maxAllowed, firstAreaName, areaCreateLabel);
|
||||
documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, blockGridDataTypeName, blockGridDataTypeId);
|
||||
await umbracoApi.document.createDefaultDocument(contentName, documentTypeId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
await umbracoUi.content.goToContentWithName(contentName);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickAddBlockGridElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickSelectBlockElementWithName(firstElementTypeName);
|
||||
await umbracoUi.content.clickLinkWithName(areaCreateLabel);
|
||||
await umbracoUi.content.clickSelectBlockElementInAreaWithName(secondElementTypeName);
|
||||
await umbracoUi.content.isTextWithExactNameVisible('Maximum 0 entries, 1 too many.');
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
await umbracoUi.content.doesErrorNotificationHaveText(NotificationConstantHelper.error.documentCouldNotBePublished);
|
||||
await umbracoUi.content.removeBlockFromArea(firstElementTypeName, firstAreaName, secondElementTypeName);
|
||||
await umbracoUi.content.clickConfirmToDeleteButton();
|
||||
await umbracoUi.content.clickSaveAndPublishButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.published);
|
||||
|
||||
// Clean
|
||||
await umbracoApi.documentType.ensureNameNotExists(secondElementTypeName);
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
import {ConstantHelper, NotificationConstantHelper, test} from '@umbraco/playwright-testhelpers';
|
||||
import {expect} from "@playwright/test";
|
||||
|
||||
let dataTypeId = '';
|
||||
const contentName = 'TestContent';
|
||||
const documentTypeName = 'TestDocumentTypeForContent';
|
||||
const dataTypeName = 'Textstring';
|
||||
const contentText = 'This is test content text';
|
||||
const referenceHeadline = 'The following items depend on this';
|
||||
const documentPickerName = ['TestPicker', 'DocumentTypeForPicker'];
|
||||
|
||||
test.beforeEach(async ({umbracoApi}) => {
|
||||
const dataTypeData = await umbracoApi.dataType.getByName(dataTypeName);
|
||||
dataTypeId = dataTypeData.id;
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
|
||||
});
|
||||
|
||||
test.afterEach(async ({umbracoApi}) => {
|
||||
await umbracoApi.document.ensureNameNotExists(contentName);
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentTypeName);
|
||||
await umbracoApi.document.emptyRecycleBin();
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName[1]);
|
||||
});
|
||||
|
||||
test('can trash an invariant content node', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
await umbracoApi.document.createDocumentWithTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list not displayed
|
||||
await umbracoUi.content.isReferenceHeadlineVisible(false);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can trash a variant content node', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
await umbracoApi.document.createDocumentWithEnglishCultureAndTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list not displayed
|
||||
await umbracoUi.content.isReferenceHeadlineVisible(false);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can trash a published content node', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoApi.document.publish(contentId);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list not displayed
|
||||
await umbracoUi.content.isReferenceHeadlineVisible(false);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can trash an invariant content node that references one item', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
// Create an invariant published content node
|
||||
const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoApi.document.publish(contentId);
|
||||
// Create a document link picker
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], contentName, contentId, documentPickerName[1]);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list
|
||||
await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
|
||||
await umbracoUi.content.doesReferenceItemsHaveCount(1);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName[0]);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can trash a variant content node that references one item', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
// Create a variant published content node
|
||||
const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithEnglishCultureAndTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoApi.document.publishDocumentWithCulture(contentId, 'en-US');
|
||||
// Create a document link picker
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], contentName, contentId, documentPickerName[1]);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list
|
||||
await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
|
||||
await umbracoUi.content.doesReferenceItemsHaveCount(1);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName[0]);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can trash an invariant content node that references more than 3 items', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const documentPickerName2 = ['TestPicker2', 'DocumentTypeForPicker2'];
|
||||
const documentPickerName3 = ['TestPicker3', 'DocumentTypeForPicker3'];
|
||||
const documentPickerName4 = ['TestPicker4', 'DocumentTypeForPicker4'];
|
||||
// Create an invariant published content node
|
||||
const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoApi.document.publish(contentId);
|
||||
// Create 4 document link pickers
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], contentName, contentId, documentPickerName[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName2[0], contentName, contentId, documentPickerName2[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName3[0], contentName, contentId, documentPickerName3[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName4[0], contentName, contentId, documentPickerName4[1]);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list has 3 items and has the text '...and one more item'
|
||||
await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
|
||||
await umbracoUi.content.doesReferenceItemsHaveCount(3);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName[0]);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName2[0]);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName3[0]);
|
||||
await umbracoUi.content.doesReferencesContainText('...and one more item');
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
|
||||
// Clean
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName2[1]);
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName3[1]);
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName4[1]);
|
||||
});
|
||||
|
||||
test('can trash a variant content node that references more than 3 items', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const documentPickerName2 = ['TestPicker2', 'DocumentTypeForPicker2'];
|
||||
const documentPickerName3 = ['TestPicker3', 'DocumentTypeForPicker3'];
|
||||
const documentPickerName4 = ['TestPicker4', 'DocumentTypeForPicker4'];
|
||||
// Create a variant published content node
|
||||
const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithEnglishCultureAndTextContent(contentName, documentTypeId, contentText, dataTypeName);
|
||||
await umbracoApi.document.publishDocumentWithCulture(contentId, 'en-US');
|
||||
// Create 4 document link pickers
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], contentName, contentId, documentPickerName[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName2[0], contentName, contentId, documentPickerName2[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName3[0], contentName, contentId, documentPickerName3[1]);
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName4[0], contentName, contentId, documentPickerName4[1]);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list has 3 items and has the text '...and one more item'
|
||||
await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
|
||||
await umbracoUi.content.doesReferenceItemsHaveCount(3);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName[0]);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName2[0]);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName3[0]);
|
||||
await umbracoUi.content.doesReferencesContainText('...and one more item');
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
|
||||
// Clean
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName2[1]);
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName3[1]);
|
||||
await umbracoApi.documentType.ensureNameNotExists(documentPickerName4[1]);
|
||||
});
|
||||
|
||||
test('can trash a content node with multiple cultures that references one item', async ({umbracoApi, umbracoUi}) => {
|
||||
// Arrange
|
||||
const firstCulture = 'en-US';
|
||||
const secondCulture = 'da';
|
||||
await umbracoApi.language.createDanishLanguage();
|
||||
// Create a content node with multiple cultures
|
||||
const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeId);
|
||||
const contentId = await umbracoApi.document.createDocumentWithTwoCulturesAndTextContent(contentName, documentTypeId, contentText, dataTypeName, firstCulture, secondCulture);
|
||||
await umbracoApi.document.publishDocumentWithCulture(contentId, firstCulture);
|
||||
await umbracoApi.document.publishDocumentWithCulture(contentId, secondCulture);
|
||||
// Create a document link picker
|
||||
await umbracoApi.document.createDefaultDocumentWithOneDocumentLink(documentPickerName[0], contentName, contentId, documentPickerName[1]);
|
||||
await umbracoUi.goToBackOffice();
|
||||
await umbracoUi.content.goToSection(ConstantHelper.sections.content);
|
||||
|
||||
// Act
|
||||
await umbracoUi.content.clickActionsMenuForContent(contentName);
|
||||
await umbracoUi.content.clickTrashButton();
|
||||
// Verify the references list
|
||||
await umbracoUi.content.doesReferenceHeadlineHaveText(referenceHeadline);
|
||||
await umbracoUi.content.doesReferenceItemsHaveCount(1);
|
||||
await umbracoUi.content.isReferenceItemNameVisible(documentPickerName[0]);
|
||||
await umbracoUi.content.clickConfirmTrashButton();
|
||||
|
||||
// Assert
|
||||
await umbracoUi.content.doesSuccessNotificationHaveText(NotificationConstantHelper.success.movedToRecycleBin);
|
||||
expect(await umbracoApi.document.doesNameExist(contentName)).toBeFalsy();
|
||||
await umbracoUi.content.isItemVisibleInRecycleBin(contentName);
|
||||
expect(await umbracoApi.document.doesItemExistInRecycleBin(contentName)).toBeTruthy();
|
||||
|
||||
// Clean
|
||||
await umbracoApi.language.ensureIsoCodeNotExists(secondCulture);
|
||||
});
|
||||
Reference in New Issue
Block a user