Skip to content

Commit

Permalink
fix(dashboard): improve UI and performance of count & disaggregation …
Browse files Browse the repository at this point in the history
…widget (#2575)

now displays multiple groupBy for different fields in a single widget

closes #2557 

Co-authored-by: Sebastian Leidig <[email protected]>
  • Loading branch information
sadaf895 and sleidig authored Oct 23, 2024
1 parent ffa150f commit 2e7b884
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 64 deletions.
32 changes: 32 additions & 0 deletions src/app/core/config/config.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,4 +676,36 @@ describe("ConfigService", () => {
},
);
}));

it("should wrap groupBy as an array if it is a string", fakeAsync(() => {
const oldConfig = {
component: "EntityCountDashboard",
config: {
entityType: "Child",
groupBy: "center", // groupBy is a string
},
};

const expectedNewConfig = {
component: "EntityCountDashboard",
config: {
entityType: "Child",
groupBy: ["center"], // groupBy should be wrapped as an array
},
};

testConfigMigration(oldConfig, expectedNewConfig);

// should not change other configs that have a groupBy property
const otherConfig = {
"view:X": {
config: {
columns: {
groupBy: "foo",
},
},
},
};
testConfigMigration(otherConfig, otherConfig);
}));
});
15 changes: 15 additions & 0 deletions src/app/core/config/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class ConfigService extends LatestEntityLoader<Config> {
migratePhotoDatatype,
migratePercentageDatatype,
migrateEntityBlock,
migrateGroupByConfig,
addDefaultNoteDetailsConfig,
];

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

return configPart;
};

const migrateGroupByConfig: ConfigMigration = (key, configPart) => {
// Check if we are working with the EntityCountDashboard component and within the 'config' object
if (
configPart?.component === "EntityCountDashboard" &&
typeof configPart?.config?.groupBy === "string"
) {
configPart.config.groupBy = [configPart.config.groupBy]; // Wrap groupBy as an array
return configPart;
}

// Return the unchanged part if no modification is needed
return configPart;
};
6 changes: 5 additions & 1 deletion src/app/core/dashboard/dashboard/dashboard.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DynamicComponentConfig } from "../../config/dynamic-components/dynamic-
import { EntityAbility } from "../../permissions/ability/entity-ability";
import { MockedTestingModule } from "../../../utils/mocked-testing.module";
import { SessionSubject } from "../../session/auth/session-info";
import { EntityCountDashboardConfig } from "app/features/dashboard-widgets/entity-count-dashboard-widget/entity-count-dashboard/entity-count-dashboard.component";

describe("DashboardComponent", () => {
let component: DashboardComponent;
Expand Down Expand Up @@ -38,7 +39,10 @@ describe("DashboardComponent", () => {
{ component: "EntityCountDashboard" },
{
component: "EntityCountDashboard",
config: { entity: "School", groupBy: "language" },
config: {
entityType: "School",
groupBy: ["language"],
} as EntityCountDashboardConfig,
},
{ component: "ShortcutDashboard", config: { shortcuts: [] } },
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,45 @@
theme="child"
[title]="totalEntities"
[subtitle]="label"
[entries]="entityGroupCounts"
[entries]="entityGroupCounts[groupBy[currentGroupIndex]]"
>
<div class="flex-row">
<button
mat-icon-button
matTooltip="Previous Grouping"
i18n-matTooltip
caption="Previous"
aria-label="Previous grouping"
(click)="getPrev()"
*ngIf="groupBy?.length > 1"
[style.transform]="'scale(0.75)'"
>
<fa-icon icon="circle-chevron-left" size="xs"></fa-icon>
</button>

<span class="flex-grow groupby-label" i18n>
by
<app-entity-field-label
[entityType]="_entity"
[field]="groupBy[currentGroupIndex]"
>
</app-entity-field-label>
</span>

<button
mat-icon-button
matTooltip="Next Grouping"
i18n-matTooltip
caption="Next"
aria-label="Next grouping"
(click)="getNext()"
*ngIf="groupBy?.length > 1"
[style.transform]="'scale(0.75)'"
>
<fa-icon icon="circle-chevron-right"></fa-icon>
</button>
</div>

<div class="table-wrapper">
<table
mat-table
Expand All @@ -13,9 +50,9 @@
>
<ng-container matColumnDef="label">
<td *matCellDef="let group">
<span *ngIf="!groupedByEntity">{{ group.label }}</span>
<span *ngIf="!group.groupedByEntity">{{ group.label }}</span>
<app-entity-block
*ngIf="groupedByEntity"
*ngIf="group.groupedByEntity"
[entityId]="group.id"
></app-entity-block>
</td>
Expand Down Expand Up @@ -46,7 +83,7 @@
<tr
mat-row
*matRowDef="let row; let i = index; columns: ['label', 'value', 'link']"
(click)="goToChildrenList(row.id)"
(click)="goToEntityList(row.id)"
class="pointer"
angulartics2On="click"
angularticsCategory="Navigation"
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
@use "../../../../core/dashboard/dashboard-widget-base";

.groupby-label {
margin: auto;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("EntityCountDashboardComponent", () => {
component = fixture.componentInstance;

component.entityType = TestEntity.ENTITY_TYPE;
component.groupBy = "category";
component.groupBy = ["category", "other", "ref"];

fixture.detectChanges();
});
Expand Down Expand Up @@ -62,16 +62,22 @@ describe("EntityCountDashboardComponent", () => {

await component.ngOnInit();

expect(component.entityGroupCounts)
const currentlyShownGroupCounts =
component.entityGroupCounts[
component.groupBy[component.currentGroupIndex]
];
expect(currentlyShownGroupCounts.length)
.withContext("unexpected number of centersWithProbability")
.toHaveSize(2);
const actualCenterAEntry = component.entityGroupCounts.filter(
.toBe(2);

const actualCenterAEntry = currentlyShownGroupCounts.filter(
(e) => e.label === centerA.label,
)[0];
expect(actualCenterAEntry.value)
.withContext("child count of CenterA not correct")
.toBe(2);
const actualCenterBEntry = component.entityGroupCounts.filter(

const actualCenterBEntry = currentlyShownGroupCounts.filter(
(e) => e.label === centerB.label,
)[0];
expect(actualCenterBEntry.value)
Expand All @@ -82,7 +88,7 @@ describe("EntityCountDashboardComponent", () => {
it("should groupBy enum values and display label", async () => {
const testGroupBy = "test";
TestEntity.schema.set(testGroupBy, { dataType: "configurable-enum" });
component.groupBy = testGroupBy;
component.groupBy = [testGroupBy];

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

await component.ngOnInit();

expect(component.entityGroupCounts).toHaveSize(3);
expect(component.entityGroupCounts).toContain({
const currentlyShownGroupCounts =
component.entityGroupCounts[
component.groupBy[component.currentGroupIndex]
];

expect(currentlyShownGroupCounts).toHaveSize(3);
expect(currentlyShownGroupCounts).toContain({
label: c1.label,
value: 2,
id: c1.id,
groupedByEntity: undefined,
});
expect(component.entityGroupCounts).toContain({
expect(currentlyShownGroupCounts).toContain({
label: c2.label,
value: 1,
id: c2.id,
groupedByEntity: undefined,
});

TestEntity.schema.delete(testGroupBy);
});

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

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

await component.ngOnInit();

expect(component.groupedByEntity).toBe(TestEntity.ENTITY_TYPE);
expect(component.entityGroupCounts).toHaveSize(2);
expect(component.entityGroupCounts).toContain({
const currentlyShownGroupCounts =
component.entityGroupCounts[
component.groupBy[component.currentGroupIndex]
];

expect(currentlyShownGroupCounts).toHaveSize(2);
expect(currentlyShownGroupCounts).toContain({
label: "",
value: 1,
id: "",
groupedByEntity: TestEntity.ENTITY_TYPE,
});
expect(component.entityGroupCounts).toContain({
expect(currentlyShownGroupCounts).toContain({
label: c1.getId(),
value: 1,
id: c1.getId(),
groupedByEntity: TestEntity.ENTITY_TYPE,
});
});

it("should groupBy arrays, split and summarized for individual array elements", async () => {
const testGroupBy = "children";
component.groupBy = testGroupBy;
component.groupBy = [testGroupBy];
component.entityType = Note.ENTITY_TYPE;

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

await component.ngOnInit();

expect(component.entityGroupCounts).toHaveSize(3);
expect(component.entityGroupCounts).toContain({
const currentlyShownGroupCounts =
component.entityGroupCounts[
component.groupBy[component.currentGroupIndex]
];

expect(currentlyShownGroupCounts).toHaveSize(3);
expect(currentlyShownGroupCounts).toContain({
label: "",
value: 1,
id: "",
groupedByEntity: "Child",
});
expect(component.entityGroupCounts).toContain({
expect(currentlyShownGroupCounts).toContain({
label: "link-1",
value: 2,
id: "link-1",
groupedByEntity: "Child",
});
expect(component.entityGroupCounts).toContain({
expect(currentlyShownGroupCounts).toContain({
label: "link-2",
value: 1,
id: "link-2",
groupedByEntity: "Child",
});
});
});
Loading

0 comments on commit 2e7b884

Please sign in to comment.