Skip to content

Commit 2e7b884

Browse files
sadaf895sleidig
andauthored
fix(dashboard): improve UI and performance of count & disaggregation widget (#2575)
now displays multiple groupBy for different fields in a single widget closes #2557 Co-authored-by: Sebastian Leidig <[email protected]>
1 parent ffa150f commit 2e7b884

File tree

8 files changed

+237
-64
lines changed

8 files changed

+237
-64
lines changed

src/app/core/config/config.service.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,4 +676,36 @@ describe("ConfigService", () => {
676676
},
677677
);
678678
}));
679+
680+
it("should wrap groupBy as an array if it is a string", fakeAsync(() => {
681+
const oldConfig = {
682+
component: "EntityCountDashboard",
683+
config: {
684+
entityType: "Child",
685+
groupBy: "center", // groupBy is a string
686+
},
687+
};
688+
689+
const expectedNewConfig = {
690+
component: "EntityCountDashboard",
691+
config: {
692+
entityType: "Child",
693+
groupBy: ["center"], // groupBy should be wrapped as an array
694+
},
695+
};
696+
697+
testConfigMigration(oldConfig, expectedNewConfig);
698+
699+
// should not change other configs that have a groupBy property
700+
const otherConfig = {
701+
"view:X": {
702+
config: {
703+
columns: {
704+
groupBy: "foo",
705+
},
706+
},
707+
},
708+
};
709+
testConfigMigration(otherConfig, otherConfig);
710+
}));
679711
});

src/app/core/config/config.service.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export class ConfigService extends LatestEntityLoader<Config> {
7272
migratePhotoDatatype,
7373
migratePercentageDatatype,
7474
migrateEntityBlock,
75+
migrateGroupByConfig,
7576
addDefaultNoteDetailsConfig,
7677
];
7778

@@ -395,3 +396,17 @@ const addDefaultNoteDetailsConfig: ConfigMigration = (key, configPart) => {
395396

396397
return configPart;
397398
};
399+
400+
const migrateGroupByConfig: ConfigMigration = (key, configPart) => {
401+
// Check if we are working with the EntityCountDashboard component and within the 'config' object
402+
if (
403+
configPart?.component === "EntityCountDashboard" &&
404+
typeof configPart?.config?.groupBy === "string"
405+
) {
406+
configPart.config.groupBy = [configPart.config.groupBy]; // Wrap groupBy as an array
407+
return configPart;
408+
}
409+
410+
// Return the unchanged part if no modification is needed
411+
return configPart;
412+
};

src/app/core/dashboard/dashboard/dashboard.component.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DynamicComponentConfig } from "../../config/dynamic-components/dynamic-
99
import { EntityAbility } from "../../permissions/ability/entity-ability";
1010
import { MockedTestingModule } from "../../../utils/mocked-testing.module";
1111
import { SessionSubject } from "../../session/auth/session-info";
12+
import { EntityCountDashboardConfig } from "app/features/dashboard-widgets/entity-count-dashboard-widget/entity-count-dashboard/entity-count-dashboard.component";
1213

1314
describe("DashboardComponent", () => {
1415
let component: DashboardComponent;
@@ -38,7 +39,10 @@ describe("DashboardComponent", () => {
3839
{ component: "EntityCountDashboard" },
3940
{
4041
component: "EntityCountDashboard",
41-
config: { entity: "School", groupBy: "language" },
42+
config: {
43+
entityType: "School",
44+
groupBy: ["language"],
45+
} as EntityCountDashboardConfig,
4246
},
4347
{ component: "ShortcutDashboard", config: { shortcuts: [] } },
4448
];

src/app/features/dashboard-widgets/entity-count-dashboard-widget/entity-count-dashboard/entity-count-dashboard.component.html

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,45 @@
33
theme="child"
44
[title]="totalEntities"
55
[subtitle]="label"
6-
[entries]="entityGroupCounts"
6+
[entries]="entityGroupCounts[groupBy[currentGroupIndex]]"
77
>
8+
<div class="flex-row">
9+
<button
10+
mat-icon-button
11+
matTooltip="Previous Grouping"
12+
i18n-matTooltip
13+
caption="Previous"
14+
aria-label="Previous grouping"
15+
(click)="getPrev()"
16+
*ngIf="groupBy?.length > 1"
17+
[style.transform]="'scale(0.75)'"
18+
>
19+
<fa-icon icon="circle-chevron-left" size="xs"></fa-icon>
20+
</button>
21+
22+
<span class="flex-grow groupby-label" i18n>
23+
by
24+
<app-entity-field-label
25+
[entityType]="_entity"
26+
[field]="groupBy[currentGroupIndex]"
27+
>
28+
</app-entity-field-label>
29+
</span>
30+
31+
<button
32+
mat-icon-button
33+
matTooltip="Next Grouping"
34+
i18n-matTooltip
35+
caption="Next"
36+
aria-label="Next grouping"
37+
(click)="getNext()"
38+
*ngIf="groupBy?.length > 1"
39+
[style.transform]="'scale(0.75)'"
40+
>
41+
<fa-icon icon="circle-chevron-right"></fa-icon>
42+
</button>
43+
</div>
44+
845
<div class="table-wrapper">
946
<table
1047
mat-table
@@ -13,9 +50,9 @@
1350
>
1451
<ng-container matColumnDef="label">
1552
<td *matCellDef="let group">
16-
<span *ngIf="!groupedByEntity">{{ group.label }}</span>
53+
<span *ngIf="!group.groupedByEntity">{{ group.label }}</span>
1754
<app-entity-block
18-
*ngIf="groupedByEntity"
55+
*ngIf="group.groupedByEntity"
1956
[entityId]="group.id"
2057
></app-entity-block>
2158
</td>
@@ -46,7 +83,7 @@
4683
<tr
4784
mat-row
4885
*matRowDef="let row; let i = index; columns: ['label', 'value', 'link']"
49-
(click)="goToChildrenList(row.id)"
86+
(click)="goToEntityList(row.id)"
5087
class="pointer"
5188
angulartics2On="click"
5289
angularticsCategory="Navigation"
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
@use "../../../../core/dashboard/dashboard-widget-base";
2+
3+
.groupby-label {
4+
margin: auto;
5+
text-align: center;
6+
overflow: hidden;
7+
text-overflow: ellipsis;
8+
}

src/app/features/dashboard-widgets/entity-count-dashboard-widget/entity-count-dashboard/entity-count-dashboard.component.spec.ts

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe("EntityCountDashboardComponent", () => {
3434
component = fixture.componentInstance;
3535

3636
component.entityType = TestEntity.ENTITY_TYPE;
37-
component.groupBy = "category";
37+
component.groupBy = ["category", "other", "ref"];
3838

3939
fixture.detectChanges();
4040
});
@@ -62,16 +62,22 @@ describe("EntityCountDashboardComponent", () => {
6262

6363
await component.ngOnInit();
6464

65-
expect(component.entityGroupCounts)
65+
const currentlyShownGroupCounts =
66+
component.entityGroupCounts[
67+
component.groupBy[component.currentGroupIndex]
68+
];
69+
expect(currentlyShownGroupCounts.length)
6670
.withContext("unexpected number of centersWithProbability")
67-
.toHaveSize(2);
68-
const actualCenterAEntry = component.entityGroupCounts.filter(
71+
.toBe(2);
72+
73+
const actualCenterAEntry = currentlyShownGroupCounts.filter(
6974
(e) => e.label === centerA.label,
7075
)[0];
7176
expect(actualCenterAEntry.value)
7277
.withContext("child count of CenterA not correct")
7378
.toBe(2);
74-
const actualCenterBEntry = component.entityGroupCounts.filter(
79+
80+
const actualCenterBEntry = currentlyShownGroupCounts.filter(
7581
(e) => e.label === centerB.label,
7682
)[0];
7783
expect(actualCenterBEntry.value)
@@ -82,7 +88,7 @@ describe("EntityCountDashboardComponent", () => {
8288
it("should groupBy enum values and display label", async () => {
8389
const testGroupBy = "test";
8490
TestEntity.schema.set(testGroupBy, { dataType: "configurable-enum" });
85-
component.groupBy = testGroupBy;
91+
component.groupBy = [testGroupBy];
8692

8793
const children = [
8894
new TestEntity(),
@@ -99,24 +105,31 @@ describe("EntityCountDashboardComponent", () => {
99105

100106
await component.ngOnInit();
101107

102-
expect(component.entityGroupCounts).toHaveSize(3);
103-
expect(component.entityGroupCounts).toContain({
108+
const currentlyShownGroupCounts =
109+
component.entityGroupCounts[
110+
component.groupBy[component.currentGroupIndex]
111+
];
112+
113+
expect(currentlyShownGroupCounts).toHaveSize(3);
114+
expect(currentlyShownGroupCounts).toContain({
104115
label: c1.label,
105116
value: 2,
106117
id: c1.id,
118+
groupedByEntity: undefined,
107119
});
108-
expect(component.entityGroupCounts).toContain({
120+
expect(currentlyShownGroupCounts).toContain({
109121
label: c2.label,
110122
value: 1,
111123
id: c2.id,
124+
groupedByEntity: undefined,
112125
});
113126

114127
TestEntity.schema.delete(testGroupBy);
115128
});
116129

117130
it("should groupBy entity references and display an entity-block", async () => {
118131
const testGroupBy = "ref";
119-
component.groupBy = testGroupBy;
132+
component.groupBy = [testGroupBy];
120133
component.entityType = TestEntity.ENTITY_TYPE;
121134

122135
const c1 = new Entity("ref-1");
@@ -128,23 +141,29 @@ describe("EntityCountDashboardComponent", () => {
128141

129142
await component.ngOnInit();
130143

131-
expect(component.groupedByEntity).toBe(TestEntity.ENTITY_TYPE);
132-
expect(component.entityGroupCounts).toHaveSize(2);
133-
expect(component.entityGroupCounts).toContain({
144+
const currentlyShownGroupCounts =
145+
component.entityGroupCounts[
146+
component.groupBy[component.currentGroupIndex]
147+
];
148+
149+
expect(currentlyShownGroupCounts).toHaveSize(2);
150+
expect(currentlyShownGroupCounts).toContain({
134151
label: "",
135152
value: 1,
136153
id: "",
154+
groupedByEntity: TestEntity.ENTITY_TYPE,
137155
});
138-
expect(component.entityGroupCounts).toContain({
156+
expect(currentlyShownGroupCounts).toContain({
139157
label: c1.getId(),
140158
value: 1,
141159
id: c1.getId(),
160+
groupedByEntity: TestEntity.ENTITY_TYPE,
142161
});
143162
});
144163

145164
it("should groupBy arrays, split and summarized for individual array elements", async () => {
146165
const testGroupBy = "children";
147-
component.groupBy = testGroupBy;
166+
component.groupBy = [testGroupBy];
148167
component.entityType = Note.ENTITY_TYPE;
149168

150169
const x0 = new Note();
@@ -157,21 +176,29 @@ describe("EntityCountDashboardComponent", () => {
157176

158177
await component.ngOnInit();
159178

160-
expect(component.entityGroupCounts).toHaveSize(3);
161-
expect(component.entityGroupCounts).toContain({
179+
const currentlyShownGroupCounts =
180+
component.entityGroupCounts[
181+
component.groupBy[component.currentGroupIndex]
182+
];
183+
184+
expect(currentlyShownGroupCounts).toHaveSize(3);
185+
expect(currentlyShownGroupCounts).toContain({
162186
label: "",
163187
value: 1,
164188
id: "",
189+
groupedByEntity: "Child",
165190
});
166-
expect(component.entityGroupCounts).toContain({
191+
expect(currentlyShownGroupCounts).toContain({
167192
label: "link-1",
168193
value: 2,
169194
id: "link-1",
195+
groupedByEntity: "Child",
170196
});
171-
expect(component.entityGroupCounts).toContain({
197+
expect(currentlyShownGroupCounts).toContain({
172198
label: "link-2",
173199
value: 1,
174200
id: "link-2",
201+
groupedByEntity: "Child",
175202
});
176203
});
177204
});

0 commit comments

Comments
 (0)