@umbraco-engage/backoffice 17.0.2 → 17.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/ab-testing/test/components/variant-picker/ab-testing-test-variant-picker.element.d.ts +2 -0
  2. package/dist/ab-testing/test/components/variant-picker/ab-testing-test-variant-picker.element.js +107 -84
  3. package/dist/ab-testing/test/modal/element/ab-testing-edit-variant-modal.element.d.ts +0 -1
  4. package/dist/ab-testing/test/modal/element/ab-testing-edit-variant-modal.element.js +2 -5
  5. package/dist/ab-testing/test/modal/token/ab-testing-edit-variant-modal.token.d.ts +0 -1
  6. package/dist/ab-testing/test/repository/detail/index.d.ts +1 -0
  7. package/dist/ab-testing/test/repository/detail/index.js +1 -0
  8. package/dist/ab-testing/test/workspace/ab-testing-test-workspace.context.d.ts +3 -2
  9. package/dist/ab-testing/test/workspace/ab-testing-test-workspace.context.js +34 -3
  10. package/dist/ab-testing/test/workspace/actions/schedule-test-action.js +4 -1
  11. package/dist/ab-testing/test/workspace/actions/start-test-action.js +1 -1
  12. package/dist/ab-testing/test/workspace/conditions/ab-testing-can-preview.condition.js +8 -1
  13. package/dist/ab-testing/test/workspace/entity-actions/preview-variant.action.js +7 -16
  14. package/dist/ab-testing/test/workspace/views/edit/ab-testing-test-editor.element.js +1 -1
  15. package/dist/analytics/analytics-context.d.ts +1 -0
  16. package/dist/analytics/analytics-context.js +4 -0
  17. package/dist/analytics/components/chart/analytics-chart.element.d.ts +1 -0
  18. package/dist/analytics/components/chart/analytics-chart.element.js +51 -24
  19. package/dist/analytics/components/chart/chart-dataset-generator.controller.js +1 -1
  20. package/dist/analytics/components/chart/chart-settings-generator.controller.d.ts +1 -1
  21. package/dist/analytics/components/chart/chart-settings-generator.controller.js +17 -5
  22. package/dist/analytics/components/chart/entities.d.ts +0 -1
  23. package/dist/analytics/components/chart/prefab-chart.element.js +0 -1
  24. package/dist/analytics/components/toggle/chart-toggle.element.d.ts +0 -1
  25. package/dist/analytics/components/toggle/chart-toggle.element.js +1 -8
  26. package/dist/core/components/chart/chart-base.element.js +3 -0
  27. package/dist/core/components/chart/chart.element.d.ts +1 -1
  28. package/dist/core/components/chart/chart.element.js +17 -16
  29. package/dist/core/components/chart/donut-chart.element.d.ts +1 -0
  30. package/dist/core/components/chart/donut-chart.element.js +25 -1
  31. package/dist/core/functions/date-utils.d.ts +7 -0
  32. package/dist/core/functions/date-utils.js +11 -0
  33. package/dist/core/lang/en.js +11 -2
  34. package/dist/core/variant-preview.controller.d.ts +1 -1
  35. package/dist/core/variant-preview.controller.js +7 -24
  36. package/dist/generated/client.gen.js +4 -1
  37. package/dist/generated/sdk.gen.d.ts +2 -1
  38. package/dist/generated/sdk.gen.js +816 -134
  39. package/dist/generated/types.gen.d.ts +26 -0
  40. package/dist/personalization/applied-personalization/editor-view/applied-personalization-editor-view.element.js +2 -2
  41. package/dist/personalization/context/personalization-editor-view-base.context.js +1 -1
  42. package/dist/personalization/personalized-variants/workspace/personalized-variant-workspace.context.js +1 -1
  43. package/dist/reporting/components/reporting-chart-card/reporting-chart-card.element.d.ts +8 -2
  44. package/dist/reporting/components/reporting-chart-card/reporting-chart-card.element.js +78 -16
  45. package/dist/reporting/components/segment-personalization/segment-personalization.element.js +7 -2
  46. package/dist/reporting/components/segment-personalization-goal-performance/segment-personalization-goal-performance.element.js +31 -47
  47. package/dist/reporting/components/segment-potential/segment-potential.element.js +7 -2
  48. package/dist/reporting/components/segment-selector/reporting-segment-selector.element.js +26 -12
  49. package/dist/reporting/screens/reporting-segments-screen.element.js +12 -6
  50. package/dist/tsconfig.build.tsbuildinfo +1 -1
  51. package/dist/umbraco-package.json +1 -1
  52. package/package.json +1 -1
@@ -4,6 +4,8 @@ declare const elementName = "ue-ab-test-variant-picker";
4
4
  export declare class UeAbTestVariantPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
5
5
  #private;
6
6
  private _test?;
7
+ private _variesBySegment;
8
+ private _editDocTypeModalPath;
7
9
  constructor();
8
10
  render(): import("lit-html").TemplateResult<1>;
9
11
  static styles: import("lit").CSSResult;
@@ -6,27 +6,40 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { css, customElement, html, state, } from "@umbraco-cms/backoffice/external/lit";
8
8
  import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
9
- import { appendToFrozenArray, partialUpdateFrozenArray, } from "@umbraco-cms/backoffice/observable-api";
9
+ import { partialUpdateFrozenArray } from "@umbraco-cms/backoffice/observable-api";
10
10
  import { ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT } from "../../workspace/index.js";
11
- import { ENGAGE_EDIT_VARIANT_PATH_PATTERN } from "../../../../core/index.js";
11
+ import { ENGAGE_EDIT_VARIANT_PATH_PATTERN, UeVariantPreviewController, } from "../../../../core/index.js";
12
12
  import { ENGAGE_AB_TESTING_EDIT_VARIANT_MODAL_ALIAS, } from "../../modal/index.js";
13
13
  import { umbOpenModal } from "@umbraco-cms/backoffice/modal";
14
14
  import { UmbModalRouteRegistrationController } from "@umbraco-cms/backoffice/router";
15
- import { UMB_DOCUMENT_ENTITY_TYPE } from "@umbraco-cms/backoffice/document";
15
+ import { UMB_DOCUMENT_DETAIL_STORE_CONTEXT, UMB_DOCUMENT_ENTITY_TYPE, } from "@umbraco-cms/backoffice/document";
16
16
  import { UMB_WORKSPACE_MODAL } from "@umbraco-cms/backoffice/workspace";
17
- import { ensurePathEndsWithSlash } from "@umbraco-cms/backoffice/utils";
18
- import { UMB_SERVER_CONTEXT } from "@umbraco-cms/backoffice/server";
17
+ import { UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT, UMB_DOCUMENT_TYPE_ENTITY_TYPE, UMB_DOCUMENT_TYPE_WORKSPACE_MODAL, UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN, } from "@umbraco-cms/backoffice/document-type";
18
+ import { firstValueFrom } from "@umbraco-cms/backoffice/external/rxjs";
19
19
  const elementName = "ue-ab-test-variant-picker";
20
20
  let UeAbTestVariantPickerElement = class UeAbTestVariantPickerElement extends UmbLitElement {
21
21
  #workspaceContext;
22
+ #previewController;
22
23
  #modalPath;
24
+ #editDocTypeModalPath;
23
25
  constructor() {
24
26
  super();
27
+ this._variesBySegment = false;
28
+ this.#previewController = new UeVariantPreviewController(this);
25
29
  this.consumeContext(ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT, (context) => {
26
30
  if (!context)
27
31
  return;
28
32
  this.#workspaceContext = context;
29
- this.observe(context.test, (test) => (this._test = test));
33
+ this.observe(context.test, async (test) => {
34
+ this._test = test;
35
+ await this.#getVariation();
36
+ });
37
+ });
38
+ new UmbModalRouteRegistrationController(this, UMB_DOCUMENT_TYPE_WORKSPACE_MODAL, Symbol())
39
+ .addAdditionalPath(UMB_DOCUMENT_TYPE_ENTITY_TYPE)
40
+ .onSubmit(() => this.#workspaceContext?.requestSave())
41
+ .observeRouteBuilder((routeBuilder) => {
42
+ this.#editDocTypeModalPath = routeBuilder({});
30
43
  });
31
44
  new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
32
45
  .addAdditionalPath(UMB_DOCUMENT_ENTITY_TYPE)
@@ -42,57 +55,51 @@ let UeAbTestVariantPickerElement = class UeAbTestVariantPickerElement extends Um
42
55
  this.#modalPath = routeBuilder({});
43
56
  });
44
57
  }
45
- async #addVariant() {
46
- if (!this._test)
58
+ async #getVariation() {
59
+ const documentUnique = this._test?.umbracoPageVariants?.[0]?.unique;
60
+ if (!documentUnique)
47
61
  return;
48
- this.#workspaceContext?.updateTest({
49
- variants: appendToFrozenArray(this._test.variants ?? [], {}),
50
- });
62
+ const documentStoreContext = await this.getContext(UMB_DOCUMENT_DETAIL_STORE_CONTEXT);
63
+ if (!documentStoreContext)
64
+ return;
65
+ const document = await firstValueFrom(documentStoreContext.byUnique(documentUnique));
66
+ if (!document)
67
+ return;
68
+ const docTypeStoreContext = await this.getContext(UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT);
69
+ if (!docTypeStoreContext)
70
+ return;
71
+ const contentType = await firstValueFrom(docTypeStoreContext.byUnique(document.documentType.unique));
72
+ this._variesBySegment = contentType?.variesBySegment ?? false;
73
+ this._editDocTypeModalPath = contentType?.unique
74
+ ? this.#editDocTypeModalPath +
75
+ UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN.generateLocal({
76
+ unique: contentType.unique,
77
+ })
78
+ : undefined;
51
79
  }
52
- async #deleteVariant(i) {
80
+ async #addVariant() {
81
+ await this.#workspaceContext?.createVariant();
82
+ }
83
+ async #deleteVariant(variant) {
53
84
  if (!this._test?.variants)
54
85
  return;
55
86
  this.#workspaceContext?.updateTest({
56
- variants: [
57
- ...this._test.variants.slice(0, i),
58
- ...this._test.variants.slice(i + 1),
59
- ],
87
+ variants: this._test.variants.filter((v) => v.id !== variant.id),
60
88
  });
61
89
  }
62
90
  async #editSinglePageVariant(variant) {
63
91
  if (!this._test || !this.#workspaceContext)
64
92
  return;
65
- if (variant.isBenchmark) {
66
- // this is the original variant, we don't want split-view.
67
- // By not providing a segment, it will open the main document editor.
68
- const url = ENGAGE_EDIT_VARIANT_PATH_PATTERN.generateLocal({
69
- unique: this._test.umbracoPageVariants[0].unique,
70
- culture: this._test.umbracoPageVariants[0].culture,
71
- });
72
- history.pushState(null, "", this.#modalPath + url);
73
- return;
74
- }
75
- // if variant is new, it will not have segment. Unfortunately that means we need to save the test,
76
- // then fetch it again, to populate the segment. The only thing we know about a new variant
77
- // is the name, so we use that to find the updated value.
78
- // This should be improved to allow creating variant segments independently of the test.
79
- if (!variant.segment) {
80
- await this.#workspaceContext.requestSave();
81
- const updated = this.#workspaceContext
82
- .getTestVariants()
83
- .find((v) => v.name === variant.name);
84
- if (!updated)
85
- return;
86
- variant = { ...variant, segment: updated.segment };
87
- }
88
- const url = ENGAGE_EDIT_VARIANT_PATH_PATTERN.generateLocal({
93
+ // no segment for benchmark variant means no split-view editing
94
+ const pathParams = {
89
95
  unique: this._test.umbracoPageVariants[0].unique,
90
96
  culture: this._test.umbracoPageVariants[0].culture,
91
- segment: variant.segment,
92
- });
97
+ segment: variant.isBenchmark ? undefined : variant.segment,
98
+ };
99
+ const url = ENGAGE_EDIT_VARIANT_PATH_PATTERN.generateLocal(pathParams);
93
100
  history.pushState(null, "", this.#modalPath + url);
94
101
  }
95
- async #editVariant(variant, label, index) {
102
+ async #editVariant(variant, label) {
96
103
  if (!this._test)
97
104
  return;
98
105
  if (this._test.testType == "SinglePage") {
@@ -103,86 +110,94 @@ let UeAbTestVariantPickerElement = class UeAbTestVariantPickerElement extends Um
103
110
  data: {
104
111
  variant,
105
112
  label,
106
- isOriginalVariant: index === 0,
107
113
  },
108
114
  }).catch(() => { });
109
115
  if (!value)
110
116
  return;
111
117
  this.#workspaceContext?.updateTest({
112
- variants: partialUpdateFrozenArray(this._test?.variants ?? [], value, (x) => this._test?.variants?.indexOf(x) === index),
118
+ variants: partialUpdateFrozenArray(this._test?.variants ?? [], value, (x) => x.id === variant.id),
113
119
  });
114
120
  }
115
121
  }
116
- async #previewVariant(variant) {
117
- const unique = this._test?.umbracoPageVariants[0].unique;
118
- const culture = this._test?.umbracoPageVariants[0].culture;
119
- const segment = variant.segment;
120
- const serverContext = await this.getContext(UMB_SERVER_CONTEXT);
121
- if (!serverContext) {
122
- throw new Error("Server context is missing");
123
- }
124
- const backofficePath = serverContext.getBackofficePath();
125
- const previewUrl = new URL(ensurePathEndsWithSlash(backofficePath) + "preview", window.location.origin);
126
- if (unique) {
127
- previewUrl.searchParams.set("id", unique);
128
- }
129
- if (culture) {
130
- previewUrl.searchParams.set("culture", culture);
131
- }
132
- if (segment) {
133
- previewUrl.searchParams.set("segment", segment);
134
- }
135
- window.open(previewUrl.toString(), `umbpreview-${unique}`);
136
- }
137
- #onNameChange(e, variant, i) {
122
+ #onNameChange(e, variant) {
138
123
  if (!this._test)
139
124
  return;
140
125
  const name = e.target.value.toString();
141
126
  this.#workspaceContext?.updateTest({
142
- variants: partialUpdateFrozenArray(this._test.variants ?? [], { ...variant, name }, (v) => this._test?.variants?.indexOf(v) === i),
127
+ variants: partialUpdateFrozenArray(this._test.variants ?? [], { ...variant, name }, (v) => v.id === variant.id),
143
128
  });
144
129
  }
145
130
  #disablePreviewButton(variant) {
146
- const result = variant.id == undefined || variant.name == null;
147
- if (this._test?.testType == "SinglePage") {
131
+ const result = variant.id === undefined || variant.name === null;
132
+ if (this._test?.testType === "SinglePage") {
148
133
  //If test type is SinglePage, also check variant id, if it's 0, means that the variant hasn't been saved yet.
149
- return result || variant.id == 0;
134
+ return result || variant.id === 0;
150
135
  }
151
136
  else {
152
137
  return result;
153
138
  }
154
139
  }
155
- #renderVariant(variant, idx) {
156
- const label = String.fromCharCode(65 + idx);
140
+ #disableDeleteButton(variant) {
141
+ if (!this._test)
142
+ return true;
143
+ return (variant.isBenchmark || !this._test.id || this._test.variants.length <= 2);
144
+ }
145
+ #renderPreviewButton(variant) {
146
+ const pageVariant = this._test?.umbracoPageVariants[0];
147
+ if (!pageVariant)
148
+ return;
149
+ const preview = () => {
150
+ this.#previewController.preview(pageVariant.unique, variant.segment ?? "", pageVariant.culture ?? undefined);
151
+ };
152
+ return html ` <uui-button
153
+ .disabled=${this.#disablePreviewButton(variant)}
154
+ .label=${this.localize.term("general_preview")}
155
+ look="secondary"
156
+ @click=${preview}
157
+ ></uui-button>`;
158
+ }
159
+ #renderVariant(variant, label) {
157
160
  return html `<div class="variant">
158
161
  <uui-input
159
162
  .value=${variant.name ?? ""}
160
- @change=${(e) => this.#onNameChange(e, variant, idx)}
163
+ @change=${(e) => this.#onNameChange(e, variant)}
161
164
  >
162
165
  <div class="extra" slot="prepend">${label}</div>
163
166
  </uui-input>
164
167
  <uui-button
165
168
  .label=${this.localize.term("general_edit")}
166
169
  look="secondary"
167
- @click=${() => this.#editVariant(variant, label, idx)}
168
- ></uui-button>
169
- <uui-button
170
- .disabled=${this.#disablePreviewButton(variant)}
171
- .label=${this.localize.term("general_preview")}
172
- look="secondary"
173
- @click=${() => this.#previewVariant(variant)}
170
+ ?disabled=${!variant.isBenchmark && !this._test?.id}
171
+ @click=${() => this.#editVariant(variant, label)}
174
172
  ></uui-button>
173
+ ${this.#renderPreviewButton(variant)}
175
174
  <uui-button
176
175
  .label=${this.localize.term("general_delete")}
177
176
  look="secondary"
178
- ?disabled=${variant.isBenchmark}
179
- @click=${() => this.#deleteVariant(idx)}
177
+ ?disabled=${this.#disableDeleteButton(variant)}
178
+ @click=${() => this.#deleteVariant(variant)}
180
179
  ><uui-icon name="icon-trash"></uui-icon
181
180
  ></uui-button>
182
181
  </div>`;
183
182
  }
183
+ #renderNoSegmentation() {
184
+ return html `<ue-empty-state>
185
+ <p style="text-align:center">
186
+ ${this.localize.term("engage_abTesting_noSegmentation")}
187
+ </p>
188
+ <uui-button
189
+ .href=${this._editDocTypeModalPath}
190
+ look="primary"
191
+ color="default"
192
+ .label=${this.localize.term("engage_editDocumentType")}
193
+ ></uui-button>
194
+ </ue-empty-state>`;
195
+ }
184
196
  render() {
185
- return html `${this._test?.variants?.map((v, i) => this.#renderVariant(v, i))}<uui-button
197
+ if (!this._variesBySegment && this._test?.testType === "SinglePage") {
198
+ return this.#renderNoSegmentation();
199
+ }
200
+ return html `${this._test?.variants?.map((v, i) => this.#renderVariant(v, String.fromCharCode(65 + i)))}<uui-button
186
201
  @click=${this.#addVariant}
187
202
  look="placeholder"
188
203
  .label=${this.localize.term("general_add")}
@@ -209,6 +224,8 @@ let UeAbTestVariantPickerElement = class UeAbTestVariantPickerElement extends Um
209
224
  align-items: center;
210
225
  border-right: 1px solid
211
226
  var(--uui-input-border-color, var(--uui-color-border));
227
+ box-sizing: border-box;
228
+ aspect-ratio: 1 / 1;
212
229
  }
213
230
 
214
231
  .variant {
@@ -221,6 +238,12 @@ let UeAbTestVariantPickerElement = class UeAbTestVariantPickerElement extends Um
221
238
  __decorate([
222
239
  state()
223
240
  ], UeAbTestVariantPickerElement.prototype, "_test", void 0);
241
+ __decorate([
242
+ state()
243
+ ], UeAbTestVariantPickerElement.prototype, "_variesBySegment", void 0);
244
+ __decorate([
245
+ state()
246
+ ], UeAbTestVariantPickerElement.prototype, "_editDocTypeModalPath", void 0);
224
247
  UeAbTestVariantPickerElement = __decorate([
225
248
  customElement(elementName)
226
249
  ], UeAbTestVariantPickerElement);
@@ -3,7 +3,6 @@ import type { UeAbTestingEditVariantModalData, UeAbTestingEditVariantModalValue
3
3
  declare const elementName = "ue-ab-testing-edit-variant-modal";
4
4
  export declare class UeAbTestingEditVariantModalElement extends UmbModalBaseElement<UeAbTestingEditVariantModalData, UeAbTestingEditVariantModalValue> {
5
5
  #private;
6
- private _variant?;
7
6
  private _variantValues;
8
7
  private _customCodeConfig?;
9
8
  connectedCallback(): void;
@@ -27,7 +27,7 @@ let UeAbTestingEditVariantModalElement = class UeAbTestingEditVariantModalElemen
27
27
  },
28
28
  },
29
29
  ];
30
- if (this.data.isOriginalVariant) {
30
+ if (this.data.variant.isBenchmark) {
31
31
  this._customCodeConfig = [
32
32
  {
33
33
  alias: "jsMessage",
@@ -57,7 +57,7 @@ let UeAbTestingEditVariantModalElement = class UeAbTestingEditVariantModalElemen
57
57
  .headline=${this.localize.term("engage_abTesting_editVariant")}
58
58
  >
59
59
  <p>
60
- ${when(this.data?.isOriginalVariant, () => this.localize.term("engage_abTesting_editOriginalVariantDescription"), () => this.localize.term("engage_abTesting_editVariantDescription"))}
60
+ ${when(this.data?.variant.isBenchmark, () => this.localize.term("engage_abTesting_editOriginalVariantDescription"), () => this.localize.term("engage_abTesting_editVariantDescription"))}
61
61
  </p>
62
62
 
63
63
  <umb-property-dataset
@@ -120,9 +120,6 @@ let UeAbTestingEditVariantModalElement = class UeAbTestingEditVariantModalElemen
120
120
  }
121
121
  `; }
122
122
  };
123
- __decorate([
124
- state()
125
- ], UeAbTestingEditVariantModalElement.prototype, "_variant", void 0);
126
123
  __decorate([
127
124
  state()
128
125
  ], UeAbTestingEditVariantModalElement.prototype, "_variantValues", void 0);
@@ -4,7 +4,6 @@ export declare const ENGAGE_AB_TESTING_EDIT_VARIANT_MODAL_ALIAS = "Engage.Modal.
4
4
  export interface UeAbTestingEditVariantModalData {
5
5
  variant: AbTestVariantDtoModel;
6
6
  label: string;
7
- isOriginalVariant: boolean;
8
7
  }
9
8
  export interface UeAbTestingEditVariantModalValue {
10
9
  name: string;
@@ -1 +1,2 @@
1
1
  export * from "./ab-testing-test-detail.repository.js";
2
+ export * from "./constants.js";
@@ -1 +1,2 @@
1
1
  export * from "./ab-testing-test-detail.repository.js";
2
+ export * from "./constants.js";
@@ -1,9 +1,9 @@
1
1
  import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
2
2
  import { type UeAbTestingTestDetailModel } from "../entities.js";
3
- import type { UeAbTestingTestDetailRepository } from "../repository/index.js";
3
+ import { type UeAbTestingTestDetailRepository } from "../repository/index.js";
4
4
  import { type AbTestDtoModel, type GoalDtoModel, type ReportingStatusModel } from "../../../generated/index.js";
5
5
  import { UeWorkspaceContextBase } from "../../../core/index.js";
6
- import { UeAbTestingProjectItemModel } from "src/ab-testing/project/entities.js";
6
+ import { UeAbTestingProjectItemModel } from "../../project/entities.js";
7
7
  export declare class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextBase<UeAbTestingTestDetailModel, UeAbTestingTestDetailRepository> {
8
8
  #private;
9
9
  readonly IS_VIEW_AWARE = true;
@@ -22,6 +22,7 @@ export declare class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextB
22
22
  getTestVariants(): import("../../../generated/index.js").AbTestVariantDtoModel[];
23
23
  load(id: string): Promise<import("@umbraco-cms/backoffice/repository").UmbRepositoryResponse<UeAbTestingTestDetailModel> | import("@umbraco-cms/backoffice/repository").UmbRepositoryResponseWithAsObservable<UeAbTestingTestDetailModel, UeAbTestingTestDetailModel>>;
24
24
  createScaffold(): Promise<UeAbTestingTestDetailModel | undefined>;
25
+ createVariant(): Promise<void>;
25
26
  delete(): Promise<void>;
26
27
  updateTest(test: Partial<AbTestDtoModel>, save?: boolean): Promise<void>;
27
28
  disableVariant(id: number): Promise<void>;
@@ -1,13 +1,13 @@
1
- import { partialUpdateFrozenArray, UmbArrayState, UmbObjectState, UmbStringState, } from "@umbraco-cms/backoffice/observable-api";
1
+ import { appendToFrozenArray, partialUpdateFrozenArray, UmbArrayState, UmbObjectState, UmbStringState, } from "@umbraco-cms/backoffice/observable-api";
2
2
  import { tryExecute } from "@umbraco-cms/backoffice/resources";
3
3
  import { ENGAGE_AB_TESTING_TEST_ENTITY_TYPE, ENGAGE_AB_TESTING_TEST_WORKSPACE_ALIAS, } from "../constants.js";
4
- import { ENGAGE_AB_TESTING_TEST_DETAIL_REPOSITORY_ALIAS } from "../repository/detail/constants.js";
4
+ import { ENGAGE_AB_TESTING_TEST_DETAIL_REPOSITORY_ALIAS, } from "../repository/index.js";
5
5
  import { UeAbTestingTestWorkspaceEditorElement } from "./ab-testing-test-workspace-editor.element.js";
6
6
  import { ABTestVariantService, GoalsService, ReportingService, } from "../../../generated/index.js";
7
7
  import { UeWorkspaceContextBase } from "../../../core/index.js";
8
8
  import { UMB_MODAL_CONTEXT } from "@umbraco-cms/backoffice/modal";
9
- import { UeAbTestingProjectItemRepository } from "src/packages.js";
10
9
  import { UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/workspace";
10
+ import { UeAbTestingProjectItemRepository } from "../../project/index.js";
11
11
  export class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextBase {
12
12
  #hostWorkspaceContext;
13
13
  #projectItemRepository;
@@ -45,6 +45,7 @@ export class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextBase {
45
45
  this.goals = this.#goals.asObservable();
46
46
  this.#activeView = new UmbStringState(undefined);
47
47
  this.activeView = this.#activeView.asObservable();
48
+ // TODO => does this actually resolve to anything?
48
49
  this.consumeContext(UMB_ENTITY_DETAIL_WORKSPACE_CONTEXT, (context) => {
49
50
  this.#hostWorkspaceContext = context;
50
51
  }).skipHost();
@@ -92,6 +93,23 @@ export class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextBase {
92
93
  });
93
94
  return data;
94
95
  }
96
+ async createVariant() {
97
+ const current = this.getData();
98
+ if (!current)
99
+ return;
100
+ const testId = current.test.id;
101
+ if (!testId)
102
+ return;
103
+ const { data } = await tryExecute(this, ABTestVariantService.postAbTestVariantCreate({
104
+ query: {
105
+ testId,
106
+ },
107
+ }));
108
+ this.updateTest({
109
+ variants: appendToFrozenArray(current.test.variants ?? [], data),
110
+ });
111
+ await this.requestSave();
112
+ }
95
113
  async delete() {
96
114
  const unique = this.getUnique();
97
115
  if (!unique)
@@ -129,6 +147,19 @@ export class UeAbTestingTestWorkspaceContext extends UeWorkspaceContextBase {
129
147
  let test = this.getData()?.test;
130
148
  if (!test)
131
149
  return;
150
+ // ensure singlePage test only have the current page variant.
151
+ // this is to avoid issues when switching test types in the editor.
152
+ // TODO => how does this work when editing in the Engage section?
153
+ if (test.testType === "SinglePage" &&
154
+ test.umbracoPageVariants?.length > 1) {
155
+ const modalContext = await this.getContext(UMB_MODAL_CONTEXT);
156
+ if (modalContext?.data.umbracoPageVariants.length) {
157
+ test = {
158
+ ...test,
159
+ umbracoPageVariants: [modalContext.data.umbracoPageVariants[0]],
160
+ };
161
+ }
162
+ }
132
163
  this.update({
133
164
  test: {
134
165
  ...test,
@@ -1,5 +1,6 @@
1
1
  import { ENGAGE_AB_TESTING_SCHEDULE_TEST_MODAL_ALIAS, } from "../../modal/index.js";
2
2
  import { UeAbTestingTestActionBase } from "./ab-test-action-base.js";
3
+ import { DateUtils } from "../../../../core/index.js";
3
4
  export class UeAbTestingTestScheduleTestWorkspaceAction extends UeAbTestingTestActionBase {
4
5
  constructor(host, args) {
5
6
  super(host, args);
@@ -12,7 +13,9 @@ export class UeAbTestingTestScheduleTestWorkspaceAction extends UeAbTestingTestA
12
13
  const { date } = modalHandler.getValue();
13
14
  if (!date)
14
15
  return;
15
- await this.workspaceContext?.updateTest({ startTime: date }, true);
16
+ // Convert local datetime-local value to UTC for server
17
+ const utcString = DateUtils.toUtcString(new Date(date));
18
+ await this.workspaceContext?.updateTest({ startTime: utcString }, true);
16
19
  }
17
20
  }
18
21
  export { UeAbTestingTestScheduleTestWorkspaceAction as api };
@@ -5,7 +5,7 @@ export class UeAbTestingTestStartTestWorkspaceAction extends UeAbTestingTestActi
5
5
  super(host, args);
6
6
  }
7
7
  async execute() {
8
- await this.workspaceContext?.updateTest({ startTime: DateUtils.format(new Date()) }, true);
8
+ await this.workspaceContext?.updateTest({ startTime: DateUtils.toUtcString(new Date()) }, true);
9
9
  }
10
10
  }
11
11
  export { UeAbTestingTestStartTestWorkspaceAction as api };
@@ -23,7 +23,14 @@ export class UeAbTestingTestCanPreviewVariantCondition extends UmbConditionBase
23
23
  ?.test.umbracoPageVariants?.at(0);
24
24
  if (!hasPageVariant)
25
25
  return;
26
- this.permitted = this.#previewableStatuses.includes(variant.status);
26
+ this.observe(context?.test, (test) => {
27
+ const testType = test?.testType;
28
+ this.permitted =
29
+ // SplitUrl does not have preview feature in Scoring tab.
30
+ this.#previewableStatuses.includes(variant.status) &&
31
+ !!variant.previewUrl &&
32
+ testType !== "SplitUrl";
33
+ });
27
34
  });
28
35
  });
29
36
  }
@@ -1,32 +1,23 @@
1
1
  import { UmbEntityActionBase, } from "@umbraco-cms/backoffice/entity-action";
2
2
  import { ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT } from "../ab-testing-test-workspace-context.token.js";
3
- import { UeVariantPreviewController } from "../../../../core/index.js";
4
3
  export class UePreviewVariantAbTestScoringAction extends UmbEntityActionBase {
5
- #preview = new UeVariantPreviewController(this);
6
- #test;
4
+ #variants;
7
5
  constructor(host, args) {
8
6
  super(host, args);
9
7
  this.consumeContext(ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT, (context) => {
10
- if (!context)
11
- return;
12
- this.observe(context?.test, (test) => {
13
- this.#test = test;
8
+ this.observe(context?.variants, (variants) => {
9
+ this.#variants = variants;
14
10
  });
15
11
  });
16
12
  }
17
13
  async execute() {
18
14
  if (!this.args.unique)
19
15
  return;
20
- const page = this.#test?.umbracoPageVariants?.[0];
21
- if (!page)
16
+ const previewUrl = this.#variants?.find((v) => v.unique === this.args.unique)?.previewUrl;
17
+ // Defensive check: previewUrl may not exist if no matching variant is found
18
+ if (!previewUrl)
22
19
  return;
23
- // unique is the key, but we need use the id for preview
24
- const id = this.#test?.variants.find((x) => x.unique === this.args.unique)?.id;
25
- if (!id)
26
- return;
27
- this.#preview?.preview(page.unique, null, page.culture, {
28
- engagePreviewAbTestVariantId: id,
29
- });
20
+ window.open(previewUrl, "_blank");
30
21
  }
31
22
  }
32
23
  export { UePreviewVariantAbTestScoringAction as api };
@@ -10,7 +10,7 @@ import { UMB_SECTION_CONTEXT } from "@umbraco-cms/backoffice/section";
10
10
  import { UMB_CONTENT_SECTION_ALIAS } from "@umbraco-cms/backoffice/content";
11
11
  import { makeArray, UePropertyDataSetRendererController, } from "../../../../../core/index.js";
12
12
  import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
13
- import { ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT } from "src/packages.js";
13
+ import { ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT } from "../../ab-testing-test-workspace-context.token.js";
14
14
  const elementName = "ue-ab-testing-test-editor";
15
15
  let UeAbTestingTestEditorElement = class UeAbTestingTestEditorElement extends UmbLitElement {
16
16
  #dataKey;
@@ -21,6 +21,7 @@ export declare class UeAnalyticsContext extends UmbContextBase {
21
21
  }>;
22
22
  updateSettings(settings: Partial<UeAnalyticsContextDefaultSettings>): void;
23
23
  setDrilldown(drilldown?: Record<string, any>): void;
24
+ updateDrilldown(drilldownUpdates: Record<string, any>): void;
24
25
  }
25
26
  export { UeAnalyticsContext as api };
26
27
  export declare const ENGAGE_ANALYTICS_CONTEXT: UmbContextToken<UeAnalyticsContext, UeAnalyticsContext>;
@@ -181,6 +181,10 @@ export class UeAnalyticsContext extends UmbContextBase {
181
181
  setDrilldown(drilldown) {
182
182
  this.#drilldown.setValue(drilldown);
183
183
  }
184
+ updateDrilldown(drilldownUpdates) {
185
+ const currentDrilldown = this.#drilldown.getValue() ?? {};
186
+ this.#drilldown.setValue({ ...currentDrilldown, ...drilldownUpdates });
187
+ }
184
188
  }
185
189
  export { UeAnalyticsContext as api };
186
190
  export const ENGAGE_ANALYTICS_CONTEXT = new UmbContextToken(ENGAGE_ANALYTICS_CONTEXT_ALIAS);
@@ -11,6 +11,7 @@ declare const elementName = "ue-chart";
11
11
  export declare class UeAnalyticsChartElement extends UeChartBaseElement {
12
12
  #private;
13
13
  config?: UeChartConfigUnionType;
14
+ showPercentages: boolean;
14
15
  percentageData?: ChartData & {
15
16
  dates: Array<Array<string>>;
16
17
  };