@umbraco-engage/backoffice 17.0.0-rc3 → 17.0.0

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 (44) hide show
  1. package/dist/ab-testing/test/workspace/views/edit/ab-testing-test-editor.element.js +30 -6
  2. package/dist/ab-testing/test/workspace/views/scoring/ab-testing-test-scoring.element.js +5 -5
  3. package/dist/analytics/analytics-context.js +4 -0
  4. package/dist/analytics/components/heatmap/heatmap.element.d.ts +0 -2
  5. package/dist/analytics/components/heatmap/heatmap.element.js +24 -29
  6. package/dist/analytics/screens/heatmap-screen.element.js +23 -3
  7. package/dist/core/components/group-box/group-box.element.js +12 -5
  8. package/dist/core/components/scoring/entities.d.ts +4 -0
  9. package/dist/core/components/scoring/scoring-base.element.d.ts +3 -2
  10. package/dist/core/components/scoring/scoring-base.element.js +147 -25
  11. package/dist/core/components/tooltip/tooltip-element.js +2 -2
  12. package/dist/core/context/entities.d.ts +1 -0
  13. package/dist/core/context/workspace-context-base.js +8 -4
  14. package/dist/core/entities.d.ts +1 -0
  15. package/dist/core/lang/{en-us.js → en.js} +5 -1
  16. package/dist/core/lang/manifests.js +1 -1
  17. package/dist/core/property/property-dataset-renderer.controller.d.ts +4 -0
  18. package/dist/core/property/property-dataset-renderer.controller.js +9 -0
  19. package/dist/generated/client.gen.js +1 -4
  20. package/dist/generated/sdk.gen.js +134 -804
  21. package/dist/generated/types.gen.d.ts +24 -6
  22. package/dist/index.js +4 -4
  23. package/dist/personalization/components/grouped-item/grouped-item-list-editor-base.element.js +1 -1
  24. package/dist/personalization/content-scoring/workspace/content-scoring-workspace-editor.element.d.ts +2 -2
  25. package/dist/personalization/content-scoring/workspace/content-scoring-workspace-editor.element.js +56 -130
  26. package/dist/personalization/content-scoring/workspace/content-scoring-workspace.context.d.ts +5 -5
  27. package/dist/personalization/content-scoring/workspace/content-scoring-workspace.context.js +25 -34
  28. package/dist/personalization/personalized-variants/editor-view/personalized-variants-editor-view.element.js +2 -2
  29. package/dist/personalization/personalized-variants/workspace/personalized-variant-workspace.context.js +3 -7
  30. package/dist/personalization/personas/repository/detail/persona-group-detail-server.data-source.js +0 -2
  31. package/dist/profiles/insights/campaigns/campaigns-list.element.d.ts +1 -0
  32. package/dist/profiles/insights/campaigns/campaigns-list.element.js +9 -1
  33. package/dist/profiles/insights/customer-journeys/customer-journeys.element.js +3 -2
  34. package/dist/profiles/insights/engage-profile-insight.interface.js +7 -1
  35. package/dist/profiles/insights/goals/goals-table-collection-view.element.js +1 -1
  36. package/dist/profiles/insights/manifests.js +2 -0
  37. package/dist/profiles/insights/persona-groups/persona-groups.element.js +3 -2
  38. package/dist/reporting/components/reporting-chart-card/reporting-chart-card.element.d.ts +1 -0
  39. package/dist/reporting/components/reporting-chart-card/reporting-chart-card.element.js +5 -1
  40. package/dist/reporting/components/segment-selector/reporting-segment-selector.element.js +10 -20
  41. package/dist/tsconfig.build.tsbuildinfo +1 -1
  42. package/dist/umbraco-package.json +1 -1
  43. package/package.json +2 -2
  44. /package/dist/core/lang/{en-us.d.ts → en.d.ts} +0 -0
@@ -22,17 +22,41 @@ let UeAbTestingTestEditorElement = class UeAbTestingTestEditorElement extends Um
22
22
  this.observe(context?.alias, (sectionAlias) => {
23
23
  if (!sectionAlias)
24
24
  return;
25
- this._setupRenderer = new UePropertyDataSetRendererController(this, ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT, AbTestSetupProperties, this.#dataKey).withItems("testType", () => {
25
+ this._setupRenderer = new UePropertyDataSetRendererController(this, ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT, AbTestSetupProperties, this.#dataKey).withItems("testType", (data) => {
26
26
  let testTypes = makeArray("ContentType", "MultiPage", "SinglePage", "SplitUrl");
27
- const testTypeToRemove = sectionAlias === UMB_CONTENT_SECTION_ALIAS
28
- ? "SplitUrl"
29
- : "SinglePage";
30
- testTypes = testTypes.filter((x) => x !== testTypeToRemove);
31
- return testTypes.map((x) => ({
27
+ // in the Engage section, we remove the incompatible test types
28
+ // only if they are not selected for this test,
29
+ let remove;
30
+ if (sectionAlias !== UMB_CONTENT_SECTION_ALIAS &&
31
+ data?.testType !== "SinglePage") {
32
+ remove = "SinglePage";
33
+ }
34
+ else if (data?.testType !== "SplitUrl") {
35
+ remove = "SplitUrl";
36
+ }
37
+ return testTypes
38
+ .filter((x) => x !== remove)
39
+ .map((x) => ({
32
40
  name: this.localize.term(`engage_abTesting_testType${x}`),
33
41
  value: x,
34
42
  }));
35
43
  });
44
+ // .withConfiguration("testType", (data) => ({
45
+ // disabled:
46
+ // sectionAlias === UMB_CONTENT_SECTION_ALIAS
47
+ // ? data?.testType === "SplitUrl"
48
+ // : data?.testType === "SinglePage",
49
+ // }))
50
+ // .withConfiguration("umbracoPageVariants", (data) => ({
51
+ // disabled:
52
+ // sectionAlias === UMB_CONTENT_SECTION_ALIAS &&
53
+ // data?.testType === "SplitUrl",
54
+ // }))
55
+ // .withConfiguration("variants", (data) => ({
56
+ // disabled:
57
+ // sectionAlias !== UMB_CONTENT_SECTION_ALIAS &&
58
+ // data?.testType === "SinglePage",
59
+ // }));
36
60
  });
37
61
  });
38
62
  this.consumeContext(ENGAGE_AB_TESTING_TEST_WORKSPACE_CONTEXT, (context) => {
@@ -82,15 +82,15 @@ let UeAbTestingTestWorkspaceViewEditElement = class UeAbTestingTestWorkspaceView
82
82
  #renderTable() {
83
83
  return html `
84
84
  ${this._test?.variants?.map((variant, idx) => html `<uui-table>
85
- <uui-table-column style="width:250px"></uui-table-column>
86
- <uui-table-column style="width:80px"></uui-table-column>
87
- <uui-table-column style="width:80px"></uui-table-column>
85
+ <uui-table-column style="min-width:250px"></uui-table-column>
86
+ <uui-table-column style="min-width:80px"></uui-table-column>
87
+ <uui-table-column style="min-width:80px"></uui-table-column>
88
88
  <uui-table-column></uui-table-column>
89
89
  <uui-table-column></uui-table-column>
90
90
  <uui-table-column></uui-table-column>
91
91
  <uui-table-column></uui-table-column>
92
- <uui-table-column style="width:100px"></uui-table-column>
93
- <uui-table-column style="width:100px"></uui-table-column>
92
+ <uui-table-column style="min-width:100px"></uui-table-column>
93
+ <uui-table-column style="min-width:100px"></uui-table-column>
94
94
  <uui-table-head>
95
95
  <uui-table-head-cell
96
96
  >${this.localize.term("engage_variant")}</uui-table-head-cell
@@ -126,6 +126,8 @@ export class UeAnalyticsContext extends UmbContextBase {
126
126
  return dateRange;
127
127
  }
128
128
  async #buildPrimaryQueryConfig(config) {
129
+ if (config.startDate && config.endDate)
130
+ return config;
129
131
  const dateRange = await this.#awaitDateRange();
130
132
  return {
131
133
  ...config,
@@ -139,6 +141,8 @@ export class UeAnalyticsContext extends UmbContextBase {
139
141
  const dateRange = await this.#awaitDateRange();
140
142
  if (!dateRange.compare)
141
143
  return;
144
+ if (config.startDate && config.endDate)
145
+ return config;
142
146
  return {
143
147
  ...config,
144
148
  ...{
@@ -10,11 +10,9 @@ export declare class UeHeatmapElement extends UmbLitElement {
10
10
  private _averageFold;
11
11
  private _pageHeight;
12
12
  private _documentUrl;
13
- private _defaultCulture;
14
13
  private _iframeBox?;
15
14
  private _iframe?;
16
15
  private _indicatorBox?;
17
- constructor();
18
16
  protected firstUpdated(): Promise<void>;
19
17
  render(): import("lit-html").TemplateResult<1>;
20
18
  static styles: import("lit").CSSResult;
@@ -8,8 +8,15 @@ import { UmbDocumentUrlRepository } from "@umbraco-cms/backoffice/document";
8
8
  import { css, customElement, html, property, query, state, when, } from "@umbraco-cms/backoffice/external/lit";
9
9
  import { UMB_APP_LANGUAGE_CONTEXT } from "@umbraco-cms/backoffice/language";
10
10
  import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
11
+ import { firstValueFrom } from "rxjs";
11
12
  const elementName = "ue-heatmap";
12
13
  let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.#documentUrlRepository = new UmbDocumentUrlRepository(this);
17
+ this._averageFold = 1080;
18
+ this._pageHeight = 0;
19
+ }
13
20
  #documentUrlRepository;
14
21
  #data;
15
22
  #querystring;
@@ -54,17 +61,6 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
54
61
  this.#generateHeatmap();
55
62
  }
56
63
  }
57
- constructor() {
58
- super();
59
- this.#documentUrlRepository = new UmbDocumentUrlRepository(this);
60
- this._averageFold = 1080;
61
- this._pageHeight = 0;
62
- this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (instance) => {
63
- this.observe(instance?.appDefaultLanguage, (value) => {
64
- this._defaultCulture = value?.unique;
65
- });
66
- });
67
- }
68
64
  async firstUpdated() {
69
65
  await this.#requestUrls();
70
66
  this.#generateHeatmap();
@@ -100,7 +96,15 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
100
96
  const { data } = await this.#documentUrlRepository.requestItems([
101
97
  this.#data.unique,
102
98
  ]);
103
- this._documentUrl = data?.[0].urls.find((x) => x.culture === (this.#data?.culture ?? this._defaultCulture))?.url;
99
+ const culture = this.#data?.culture ?? (await this.#getDefaultCulture());
100
+ this._documentUrl = data?.[0].urls.find((x) => x.culture === culture)?.url;
101
+ }
102
+ async #getDefaultCulture() {
103
+ const context = await this.getContext(UMB_APP_LANGUAGE_CONTEXT);
104
+ if (!context)
105
+ return undefined;
106
+ const appDefaultLanguage = await firstValueFrom(context.appDefaultLanguage);
107
+ return appDefaultLanguage?.unique ?? undefined;
104
108
  }
105
109
  #generateHeatmap() {
106
110
  if (!this._documentUrl || !this._iframe)
@@ -113,7 +117,7 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
113
117
  this._iframe.src = this._documentUrl + this.#querystring;
114
118
  }
115
119
  #renderHeatmap() {
116
- return when(!this.#data?.visitorPercentagesPerPixel?.length, () => html `<div id="no-data">
120
+ return when(!this.#data?.visitorPercentagesPerPixel?.length, () => html `<uui-box>
117
121
  <p>${this.localize.term("engage_analytics_heatmapNoData")}</p>
118
122
  <uui-button
119
123
  look="primary"
@@ -121,7 +125,8 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
121
125
  target="_blank"
122
126
  label=${this.localize.term("engage_learnMore")}
123
127
  ></uui-button>
124
- </div>`, () => html `<div id="iframe-box">
128
+ </uui-box>`, () => html `<div id="main">
129
+ <div id="iframe-box">
125
130
  <div class="scrollmap"></div>
126
131
  <div class="scrollmap blend"></div>
127
132
  <div id="lines">
@@ -153,18 +158,19 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
153
158
  <span>${this.localize.term("engage_hot")}</span>
154
159
  <div id="legend-gradient"></div>
155
160
  <span>${this.localize.term("engage_cold")}</span>
156
- </div>`);
161
+ </div>
162
+ </div>`);
157
163
  }
158
164
  #renderNoUrl() {
159
- return html `<div id="no-data">
165
+ return html `<uui-box>
160
166
  <p>${this.localize.term("engage_analytics_heatmapNoUrl")}</p>
161
- </div>`;
167
+ </uui-box>`;
162
168
  }
163
169
  render() {
164
170
  return when(this._documentUrl, () => this.#renderHeatmap(), () => this.#renderNoUrl());
165
171
  }
166
172
  static { this.styles = css `
167
- :host {
173
+ #main {
168
174
  border: 1px solid var(--uui-color-border);
169
175
  border-radius: var(--uui-border-radius);
170
176
  padding: var(--uui-size-layout-1);
@@ -219,14 +225,6 @@ let UeHeatmapElement = class UeHeatmapElement extends UmbLitElement {
219
225
  mix-blend-mode: darken;
220
226
  }
221
227
 
222
- #no-data {
223
- display: flex;
224
- flex-direction: column;
225
- align-items: center;
226
- justify-content: center;
227
- text-align: center;
228
- }
229
-
230
228
  #indicator {
231
229
  position: absolute;
232
230
  left: 0;
@@ -359,9 +357,6 @@ __decorate([
359
357
  __decorate([
360
358
  state()
361
359
  ], UeHeatmapElement.prototype, "_documentUrl", void 0);
362
- __decorate([
363
- state()
364
- ], UeHeatmapElement.prototype, "_defaultCulture", void 0);
365
360
  __decorate([
366
361
  query("#iframe-box")
367
362
  ], UeHeatmapElement.prototype, "_iframeBox", void 0);
@@ -11,6 +11,8 @@ import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/document
11
11
  import { tryExecute } from "@umbraco-cms/backoffice/resources";
12
12
  import { makeArray, } from "../../core/index.js";
13
13
  import { HeatmapsService, } from "../../generated/index.js";
14
+ import { UMB_APP_LANGUAGE_CONTEXT } from "@umbraco-cms/backoffice/language";
15
+ import { firstValueFrom } from "@umbraco-cms/backoffice/external/rxjs";
14
16
  const elementName = "ue-analytics-heatmap";
15
17
  let UeAnalyticsHeatmapElement = class UeAnalyticsHeatmapElement extends UmbLitElement {
16
18
  constructor() {
@@ -22,8 +24,7 @@ let UeAnalyticsHeatmapElement = class UeAnalyticsHeatmapElement extends UmbLitEl
22
24
  if (!context)
23
25
  return;
24
26
  this._documentUnique = context.getUnique()?.toString();
25
- this._documentCulture =
26
- context.splitView.getActiveVariants()[0]?.culture ?? undefined;
27
+ this._documentCulture = context.splitView.getActiveVariants()[0]?.culture;
27
28
  await this.#getHeatmapPageVariants();
28
29
  });
29
30
  this.consumeContext(ENGAGE_ANALYTICS_CONTEXT, (context) => {
@@ -35,9 +36,22 @@ let UeAnalyticsHeatmapElement = class UeAnalyticsHeatmapElement extends UmbLitEl
35
36
  });
36
37
  });
37
38
  }
39
+ async #getDefaultCulture() {
40
+ const context = await this.getContext(UMB_APP_LANGUAGE_CONTEXT);
41
+ if (!context)
42
+ return undefined;
43
+ const appDefaultLanguage = await firstValueFrom(context.appDefaultLanguage);
44
+ return appDefaultLanguage?.unique ?? undefined;
45
+ }
38
46
  async #getHeatmapPageVariants() {
47
+ this._documentCulture ??= await this.#getDefaultCulture();
48
+ if (!this._documentUnique)
49
+ return;
39
50
  const { data } = await tryExecute(this, HeatmapsService.getHeatmapsVariants({
40
- query: { unique: this._documentUnique, culture: this._documentCulture },
51
+ query: {
52
+ unique: this._documentUnique,
53
+ culture: this._documentCulture,
54
+ },
41
55
  }));
42
56
  this._variants =
43
57
  data
@@ -52,6 +66,7 @@ let UeAnalyticsHeatmapElement = class UeAnalyticsHeatmapElement extends UmbLitEl
52
66
  }
53
67
  }
54
68
  async #getHeatmap() {
69
+ this._documentCulture ??= await this.#getDefaultCulture();
55
70
  if (!this._documentUnique)
56
71
  return;
57
72
  this._loading = true;
@@ -170,6 +185,11 @@ let UeAnalyticsHeatmapElement = class UeAnalyticsHeatmapElement extends UmbLitEl
170
185
  .header-control {
171
186
  display: flex;
172
187
  flex-direction: column;
188
+
189
+ uui-select {
190
+ height: 100%;
191
+ --uui-select-height: 100%;
192
+ }
173
193
  }
174
194
  `; }
175
195
  };
@@ -28,10 +28,11 @@ let UeGroupBoxElement = class UeGroupBoxElement extends UmbLitElement {
28
28
  ${when(this._iconUrl, () => html `<img .src=${this._iconUrl} alt="" />`)}
29
29
  </div>
30
30
  <div id="content">
31
- <strong>${this.name}</strong><small>${this.description}</small>
31
+ <strong>${this.name}</strong>${when(this.description, (desc) => html `<small>${desc}</small>`)}
32
+ <slot name="secondary"></slot>
32
33
  </div>
33
34
  </div>
34
- <slot id="content-slot"></slot>
35
+ <slot id="content-slot" name="primary"></slot>
35
36
  <slot name="actions"></slot> `;
36
37
  }
37
38
  static { this.styles = css `
@@ -40,10 +41,15 @@ let UeGroupBoxElement = class UeGroupBoxElement extends UmbLitElement {
40
41
  gap: var(--uui-size-5);
41
42
  }
42
43
 
44
+ slot {
45
+ display: contents;
46
+ }
47
+
43
48
  #step {
44
49
  display: flex;
45
50
  gap: var(--uui-size-5);
46
- width: 60%;
51
+ max-width: 75%;
52
+ flex: 1;
47
53
  }
48
54
 
49
55
  #bar {
@@ -69,18 +75,19 @@ let UeGroupBoxElement = class UeGroupBoxElement extends UmbLitElement {
69
75
  display: flex;
70
76
  flex-direction: column;
71
77
  min-width: 150px;
78
+ flex: 1;
72
79
 
73
80
  small {
74
81
  line-height: 1.4;
75
82
  }
76
83
  }
77
84
 
78
- #content-slot {
85
+ ::slotted([slot="primary"]) {
79
86
  margin-left: auto;
80
87
  display: flex;
81
88
  }
82
89
 
83
- slot[name="actions"] {
90
+ ::slotted([slot="actions"]) {
84
91
  align-self: center;
85
92
  display: block;
86
93
  }
@@ -1,7 +1,11 @@
1
+ import { MinimumDeviationTypeModel } from "src/generated/types.gen";
1
2
  export interface UeScoreableGroupModel {
2
3
  title?: string | null;
3
4
  upperScoreLimit?: number | null;
4
5
  items: Array<UeScoreableItemModel>;
6
+ minimumDeviation?: number | null;
7
+ minimumDeviationType?: MinimumDeviationTypeModel;
8
+ minimumParticipationScoreThreshold?: number | null;
5
9
  }
6
10
  export interface UeScoringElementConfig {
7
11
  hideDivider?: boolean;
@@ -9,7 +9,7 @@ export declare abstract class UeScoringBaseElement<GroupModel extends UeScoreabl
9
9
  protected items: GroupModel[];
10
10
  value: UeEntityScoreModel[];
11
11
  config?: UeScoringElementConfig;
12
- inert: boolean;
12
+ readonly: boolean;
13
13
  private _hideDivider;
14
14
  constructor(repositoryCtor: UeDetailRepositoryConstructor<GroupModel>, dividerText?: string);
15
15
  connectedCallback(): Promise<void>;
@@ -17,7 +17,8 @@ export declare abstract class UeScoringBaseElement<GroupModel extends UeScoreabl
17
17
  target: HTMLInputElement;
18
18
  }, id: number, upperScoreLimit: number): void;
19
19
  getValue(id: number): number;
20
+ getItem(id: number): UeEntityScoreModel | undefined;
20
21
  renderGroup(group: GroupModel): import("lit-html").TemplateResult<1>;
21
22
  render(): import("lit-html").TemplateResult<1> | undefined;
22
- static styles: import("lit").CSSResult;
23
+ static styles: import("lit").CSSResult[];
23
24
  }
@@ -9,6 +9,7 @@ import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element";
9
9
  import { appendToFrozenArray } from "@umbraco-cms/backoffice/observable-api";
10
10
  import { UmbChangeEvent } from "@umbraco-cms/backoffice/event";
11
11
  import { UmbId } from "@umbraco-cms/backoffice/id";
12
+ import { UUITextStyles } from "@umbraco-cms/backoffice/external/uui";
12
13
  export class UeScoringBaseElement extends UmbLitElement {
13
14
  #dividerText;
14
15
  constructor(repositoryCtor, dividerText) {
@@ -16,7 +17,7 @@ export class UeScoringBaseElement extends UmbLitElement {
16
17
  this.defaultUpperScoreLimit = 10;
17
18
  this.items = [];
18
19
  this.value = [];
19
- this.inert = false;
20
+ this.readonly = false;
20
21
  this._hideDivider = false;
21
22
  this.repository = new repositoryCtor(this);
22
23
  this.#dividerText = dividerText;
@@ -49,13 +50,93 @@ export class UeScoringBaseElement extends UmbLitElement {
49
50
  getValue(id) {
50
51
  return this.value?.find((x) => x.entityId === id)?.score ?? 0;
51
52
  }
52
- #renderReadonly(item) {
53
- return html `<uui-tag look="secondary">${this.getValue(item.id)}</uui-tag>`;
53
+ getItem(id) {
54
+ return this.value?.find((x) => x.entityId === id);
55
+ }
56
+ #renderReadonly(src, group) {
57
+ const item = this.getItem(src.id);
58
+ // if no item, the score is 0
59
+ // but we still want to show the empty default state
60
+ if (!item) {
61
+ return html `
62
+ <div slot="primary">
63
+ <uui-tag look="secondary"> 0 </uui-tag>
64
+ </div>
65
+ <uui-progress-bar progress="0" slot="secondary"></uui-progress-bar>
66
+ `;
67
+ }
68
+ const itemFromGroup = group.items.find((x) => x.id === item.entityId);
69
+ const groupItemIds = group.items.map((x) => x.id);
70
+ // we need all items ordered to calculate deviation as we compare the max to the second highest
71
+ // but all other items compare to the max.
72
+ const sortedGroupItems = this.value
73
+ .filter((x) => groupItemIds.includes(x.entityId))
74
+ .sort((a, b) => b.score - a.score);
75
+ let diff = 0;
76
+ // for non-max items, compare to the max.
77
+ if (sortedGroupItems[0]?.entityId !== item.entityId) {
78
+ diff = sortedGroupItems[0].score - item.score;
79
+ }
80
+ else {
81
+ // for the max item, chekk if it meets the minimum deviation compared to the second highest
82
+ diff = item.score - (sortedGroupItems[1]?.score ?? 0);
83
+ }
84
+ let minDiff = group.minimumDeviation ?? 1;
85
+ if (group.minimumDeviationType === "Percent") {
86
+ minDiff = item.score * (minDiff / 100);
87
+ }
88
+ const withinDeviation = diff < minDiff;
89
+ // if progress is >= 100, but isActive is false, assume deviation not met
90
+ const progress = (item.score / (group.minimumParticipationScoreThreshold ?? 1)) * 100;
91
+ const meetsThreshold = progress >= 100;
92
+ const activeColor = meetsThreshold
93
+ ? !item.isActive
94
+ ? "var(--uui-color-border-emphasis)"
95
+ : itemFromGroup?.color?.value
96
+ : "default";
97
+ const progressColor = meetsThreshold
98
+ ? !item.isActive
99
+ ? "var(--uui-color-border-emphasis)"
100
+ : itemFromGroup?.color?.value
101
+ : "var(--uui-color-border)";
102
+ let tooltip;
103
+ if (item.isActive) {
104
+ tooltip = this.localize.term("engage_scoringTooltipActiveItem", itemFromGroup?.title);
105
+ }
106
+ else if (meetsThreshold && !item.isActive && withinDeviation) {
107
+ tooltip = this.localize.term("engage_scoringTooltipInactiveMeetsThresholdWithinDeviation", itemFromGroup?.title);
108
+ }
109
+ else if (meetsThreshold && !withinDeviation && !item.isActive) {
110
+ const activeItemId = this.value.find((x) => x.isActive && groupItemIds.includes(x.entityId))?.entityId;
111
+ const activeItem = group.items.find((x) => x.id === activeItemId);
112
+ tooltip = this.localize.term("engage_scoringTooltipInactiveMeetsThresholdNotWithinDeviation", itemFromGroup?.title, activeItem?.title);
113
+ }
114
+ return html `<div
115
+ slot="primary"
116
+ style="display:flex; align-items:center"
117
+ popovertarget="popover-${item.entityId}"
118
+ >
119
+ <uui-tag
120
+ style="--color: ${activeColor}"
121
+ look=${meetsThreshold ? "primary" : "secondary"}
122
+ >
123
+ ${item.score}
124
+ </uui-tag>
125
+ ${when(tooltip, () => html ` <uui-popover-container id="popover-${item.entityId}">
126
+ <ue-tooltip hint> ${tooltip}</ue-tooltip>
127
+ </uui-popover-container>`)}
128
+ </div>
129
+ <uui-progress-bar
130
+ style="--uui-color-positive: ${progressColor}"
131
+ progress=${progress}
132
+ slot="secondary"
133
+ ></uui-progress-bar> `;
54
134
  }
55
135
  #renderEditor(item, group) {
56
136
  if (group.upperScoreLimit &&
57
137
  group.upperScoreLimit > this.defaultUpperScoreLimit) {
58
138
  return html `<uui-input
139
+ slot="primary"
59
140
  type="number"
60
141
  max=${group.upperScoreLimit}
61
142
  min="0"
@@ -64,25 +145,41 @@ export class UeScoringBaseElement extends UmbLitElement {
64
145
  ></uui-input>`;
65
146
  }
66
147
  return html `<umb-input-slider
148
+ slot="primary"
67
149
  .max=${group.upperScoreLimit ?? this.defaultUpperScoreLimit}
68
150
  @change=${(e) => this.onValueChange(e, item.id, group.upperScoreLimit)}
69
151
  .valueLow=${this.getValue(item.id)}
70
152
  ></umb-input-slider>`;
71
153
  }
72
154
  renderGroup(group) {
73
- return html `<uui-box .headline=${group.title ?? ""}>
74
- ${when(group.upperScoreLimit !== this.defaultUpperScoreLimit, () => html ` <div slot="header-actions">
75
- ${this.localize.term("engage_scoreFromTo", group.upperScoreLimit)}
76
- </div>`)}
155
+ return html `<div class="scoring-group">
156
+ <div id="header" class="uui-text">
157
+ <h5 class="uui-h5">${group.title}</h5>
158
+ ${when(group.upperScoreLimit !== this.defaultUpperScoreLimit &&
159
+ !this.readonly, () => this.localize.term("engage_scoreFromTo", group.upperScoreLimit))}
160
+ </div>
161
+
77
162
  ${group.items.map((item) => html `<ue-group-box
78
163
  style="${`--engage-bar-color: ${item.color?.value}`}"
79
164
  .name=${item.title}
80
- .description=${item.description}
165
+ .description=${this.readonly ? null : item.description}
81
166
  .iconUrl=${item.iconUrl}
82
167
  >
83
- ${when(this.inert, () => this.#renderReadonly(item), () => this.#renderEditor(item, group))}
168
+ ${when(this.readonly, () => this.#renderReadonly(item, group), () => this.#renderEditor(item, group))}
84
169
  </ue-group-box>`)}
85
- </uui-box>`;
170
+ ${when(this.readonly, () => html ` <small>
171
+ <span
172
+ >Minimal deviation:
173
+ ${group.minimumDeviation}${group.minimumDeviationType ===
174
+ "Percent"
175
+ ? "%"
176
+ : ""}</span
177
+ ><span>|</span
178
+ ><span>
179
+ Threshold value: ${group.minimumParticipationScoreThreshold}</span
180
+ >
181
+ </small>`)}
182
+ </div>`;
86
183
  }
87
184
  render() {
88
185
  if (!this.items.length)
@@ -90,23 +187,48 @@ export class UeScoringBaseElement extends UmbLitElement {
90
187
  return html ` ${when(this._hideDivider === false, () => html `<ue-divider .text=${this.#dividerText}></ue-divider>`)}
91
188
  ${this.items.map((group) => this.renderGroup(group))}`;
92
189
  }
93
- static { this.styles = css `
94
- uui-box {
95
- height: var(--content-height, auto);
96
- }
190
+ static { this.styles = [
191
+ UUITextStyles,
192
+ css `
193
+ .scoring-group {
194
+ height: var(--content-height, auto);
195
+ display: flex;
196
+ flex-direction: column;
197
+ }
97
198
 
98
- ue-group-box + ue-group-box {
99
- margin-top: var(--uui-size-2);
100
- }
199
+ ue-group-box + ue-group-box {
200
+ margin-top: var(--uui-size-2);
201
+ }
101
202
 
102
- uui-box + uui-box {
103
- margin-top: var(--group-gap, var(--uui-size-3));
104
- }
203
+ .scoring-group + .scoring-group {
204
+ margin-top: var(--group-gap, var(--uui-size-space-5));
205
+ }
105
206
 
106
- uui-tag {
107
- align-self: center;
108
- }
109
- `; }
207
+ uui-tag {
208
+ align-self: center;
209
+ }
210
+
211
+ small {
212
+ display: flex;
213
+ padding-top: var(--uui-size-3);
214
+ margin-top: auto;
215
+ gap: var(--uui-size-2);
216
+ }
217
+
218
+ small span {
219
+ display: block;
220
+ }
221
+
222
+ /* from uui-box */
223
+ #header {
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: space-between;
227
+ padding-right: var(--uui-size-space-5);
228
+ margin-bottom: var(--uui-size-space-2);
229
+ }
230
+ `,
231
+ ]; }
110
232
  }
111
233
  __decorate([
112
234
  state()
@@ -119,7 +241,7 @@ __decorate([
119
241
  ], UeScoringBaseElement.prototype, "config", void 0);
120
242
  __decorate([
121
243
  property({ type: Boolean, reflect: true })
122
- ], UeScoringBaseElement.prototype, "inert", void 0);
244
+ ], UeScoringBaseElement.prototype, "readonly", void 0);
123
245
  __decorate([
124
246
  state()
125
247
  ], UeScoringBaseElement.prototype, "_hideDivider", void 0);
@@ -32,8 +32,8 @@ let UeTooltipElement = class UeTooltipElement extends UmbLitElement {
32
32
  this.#unbindListeners();
33
33
  }
34
34
  #bindListeners() {
35
- this.#trigger = this.getHostElement().closest("[popovertarget]") ?? undefined;
36
- this.#host = this.getHostElement().closest("uui-popover-container") ?? undefined;
35
+ this.#trigger = this.getHostElement().closest("[popovertarget]");
36
+ this.#host = this.getHostElement().closest("uui-popover-container");
37
37
  if (!this.#trigger || !this.#host) {
38
38
  console.warn("UeTooltipElement[hint] requires a uui-popover-container and a popovertarget element to function properly.");
39
39
  return;
@@ -10,4 +10,5 @@ export interface UeValidatedWorkspaceContextArgs {
10
10
  detailRepositoryAlias: string;
11
11
  routedComponents?: UeRoutedComponentsConfiguration;
12
12
  actions?: Array<UeWorkspaceAction>;
13
+ withRedirectOnCreate?: boolean;
13
14
  }
@@ -23,7 +23,7 @@ export class UeWorkspaceContextBase extends UmbEntityDetailWorkspaceContextBase
23
23
  // we don't use the value anywhere, hence the garbage-in below.
24
24
  // Note this is obsolete, and will be removed in v18, so will need to be revisited.
25
25
  this.setParent({ entityType: "engage-entity-root", unique: "" });
26
- this.#setRoutes(args.routedComponents);
26
+ this.#setRoutes(args.routedComponents, args.withRedirectOnCreate ?? true);
27
27
  this.#registerActions(args.actions);
28
28
  }
29
29
  #registerActions(actions) {
@@ -54,7 +54,7 @@ export class UeWorkspaceContextBase extends UmbEntityDetailWorkspaceContextBase
54
54
  });
55
55
  });
56
56
  }
57
- #setRoutes(routedComponents) {
57
+ #setRoutes(routedComponents, withRedirectOnCreate) {
58
58
  if (!routedComponents)
59
59
  return;
60
60
  this.routes.setRoutes([
@@ -62,7 +62,9 @@ export class UeWorkspaceContextBase extends UmbEntityDetailWorkspaceContextBase
62
62
  path: "edit/:id",
63
63
  component: routedComponents.edit,
64
64
  setup: async (_component, info) => {
65
- this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
65
+ withRedirectOnCreate
66
+ ? this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias)
67
+ : {};
66
68
  await this.load(info.match.params.id);
67
69
  },
68
70
  },
@@ -73,7 +75,9 @@ export class UeWorkspaceContextBase extends UmbEntityDetailWorkspaceContextBase
73
75
  await this.createScaffold({
74
76
  parent: { entityType: "engage-entity-root", unique: "" },
75
77
  });
76
- new UmbWorkspaceIsNewRedirectController(this, this, this.getHostElement().shadowRoot.querySelector("umb-router-slot"));
78
+ withRedirectOnCreate
79
+ ? new UmbWorkspaceIsNewRedirectController(this, this, this.getHostElement().shadowRoot.querySelector("umb-router-slot"))
80
+ : {};
77
81
  },
78
82
  },
79
83
  ]);
@@ -72,6 +72,7 @@ export interface UeEntityScoreModel {
72
72
  score: number;
73
73
  id: number;
74
74
  unique: string;
75
+ isActive?: boolean;
75
76
  entityId: number;
76
77
  }
77
78
  export interface UeLicensedFeaturesMap {