Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unrelated changes #2196

Merged
merged 34 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6f2432a
added test for adding unrelated note
TheSlimvReal Jan 23, 2024
821972a
`loadData` function returns result instead of initializing it and ren…
TheSlimvReal Jan 23, 2024
454d313
using same filter logic to initialize data and pass to entities table
TheSlimvReal Jan 23, 2024
c86df39
some code cleanups
TheSlimvReal Jan 23, 2024
b90f7a9
added related property for related notes
TheSlimvReal Jan 23, 2024
3fa13de
inferring related property
TheSlimvReal Jan 23, 2024
473d6b4
added multi property support
TheSlimvReal Jan 23, 2024
e5e4ebe
removed overwrites of `property`
TheSlimvReal Jan 23, 2024
c54ef74
using different approach to update table summary
TheSlimvReal Jan 23, 2024
5a61f1d
updated documentation
TheSlimvReal Jan 23, 2024
9e894dd
correctly setting showInactive toggle in child school overview
TheSlimvReal Jan 23, 2024
0dc0c09
using placeholder instead of new record factory
TheSlimvReal Jan 23, 2024
f030a6a
added todos
TheSlimvReal Jan 23, 2024
b392171
removed unnecessary sorts
TheSlimvReal Jan 24, 2024
4ada0ed
removed unnecessary data filter
TheSlimvReal Jan 24, 2024
4340bc0
not using properties in tests
TheSlimvReal Jan 24, 2024
cdfbfa6
generalized newRecordFactory
TheSlimvReal Jan 24, 2024
366f4c6
aligned new record factory names
TheSlimvReal Jan 24, 2024
48975c1
fixed color highlighting for child school overview
TheSlimvReal Jan 24, 2024
5a16564
small cleanups
TheSlimvReal Jan 24, 2024
2957df5
code cleanups
TheSlimvReal Jan 24, 2024
bbc96e9
Update src/app/core/entity-details/related-entities/related-entities.…
TheSlimvReal Jan 31, 2024
f5ccc48
Merge branch 'master' into fix_unrelated_changes
TheSlimvReal Feb 1, 2024
0e1c6c6
fixed setting of invalid properties
TheSlimvReal Feb 1, 2024
3ef41a2
Merge branch 'master' into fix_unrelated_changes
TheSlimvReal Feb 1, 2024
8791493
added option to set relation property
TheSlimvReal Feb 2, 2024
209e4aa
added fallback handling to Todos list if multiple related properties …
TheSlimvReal Feb 2, 2024
ada0e08
fixed tests
TheSlimvReal Feb 2, 2024
4fccb15
Merge branch 'master' into fix_unrelated_changes
sleidig Feb 2, 2024
1e6ca4e
remove AserComponent in favor of simple RelatedEntities
sleidig Feb 2, 2024
e58e78d
remove Health and BMI related components in favor of generic RelatedE…
sleidig Feb 2, 2024
c5d4248
Merge remote-tracking branch 'origin/master' into fix_unrelated_changes
sleidig Feb 2, 2024
25d2982
improved doc
TheSlimvReal Feb 5, 2024
51daedd
Merge branch 'master' into fix_unrelated_changes
TheSlimvReal Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export class ActivitiesOverviewComponent
implements OnInit
{
entityCtr = RecurringActivity;
property = "linkedGroups";

titleColumn: FormFieldConfig = {
id: "title",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { EntitiesTableComponent } from "../../../core/common-components/entities
standalone: true,
})
export class AttendanceDetailsComponent {
@Input() entity: ActivityAttendance = new ActivityAttendance();
@Input() entity: ActivityAttendance;
@Input() forChild: string;
EventNote = EventNote;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { RelatedEntitiesComponent } from "../../../../core/entity-details/relate
import { EntityMapperService } from "../../../../core/entity/entity-mapper/entity-mapper.service";
import { EntityRegistry } from "../../../../core/entity/database-entity.decorator";
import { ScreenWidthObserver } from "../../../../utils/media/screen-size-observer.service";
import { FilterService } from "../../../../core/filter/filter.service";

@DynamicComponent("Aser")
@Component({
Expand All @@ -21,7 +22,6 @@ import { ScreenWidthObserver } from "../../../../utils/media/screen-size-observe
})
export class AserComponent extends RelatedEntitiesComponent<Aser> {
@Input() entity: Child;
property = "child";
entityCtr = Aser;

override _columns: FormFieldConfig[] = [
Expand All @@ -38,16 +38,12 @@ export class AserComponent extends RelatedEntitiesComponent<Aser> {
entityMapper: EntityMapperService,
entityRegistry: EntityRegistry,
screenWidthObserver: ScreenWidthObserver,
filterService: FilterService,
) {
super(entityMapper, entityRegistry, screenWidthObserver);
super(entityMapper, entityRegistry, screenWidthObserver, filterService);
}

override async initData() {
this.data = (
await this.childrenService.getAserResultsOfChild(this.entity.getId())
).sort(
(a, b) =>
(b.date ? b.date.valueOf() : 0) - (a.date ? a.date.valueOf() : 0),
);
override getData() {
return this.childrenService.getAserResultsOfChild(this.entity.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,24 @@ import { Entity } from "../../../../core/entity/model/entity";
import { DatabaseEntity } from "../../../../core/entity/database-entity.decorator";
import { DatabaseField } from "../../../../core/entity/database-field.decorator";
import { ConfigurableEnumValue } from "../../../../core/basic-datatypes/configurable-enum/configurable-enum.interface";
import { EntityDatatype } from "../../../../core/basic-datatypes/entity/entity.datatype";
import { Child } from "../../model/child";
import { PLACEHOLDERS } from "../../../../core/entity/schema/entity-schema-field";

@DatabaseEntity("EducationalMaterial")
export class EducationalMaterial extends Entity {
static create(params: Partial<EducationalMaterial>): EducationalMaterial {
return Object.assign(new EducationalMaterial(), params);
}

@DatabaseField() child: string; // id of Child entity
@DatabaseField({
dataType: EntityDatatype.dataType,
additional: Child.ENTITY_TYPE,
})
child: string; // id of Child entity
@DatabaseField({
label: $localize`:Date on which the material has been borrowed:Date`,
defaultValue: PLACEHOLDERS.NOW,
})
date: Date;
@DatabaseField({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Component, Input, OnInit } from "@angular/core";
import { Component } from "@angular/core";
import { HealthCheck } from "../model/health-check";
import { ChildrenService } from "../../children.service";
import { Child } from "../../model/child";
import { FormFieldConfig } from "../../../../core/common-components/entity-form/FormConfig";
import { DynamicComponent } from "../../../../core/config/dynamic-components/dynamic-component.decorator";
import { EntitiesTableComponent } from "../../../../core/common-components/entities-table/entities-table.component";
import { RelatedEntitiesComponent } from "../../../../core/entity-details/related-entities/related-entities.component";
import { EntityMapperService } from "../../../../core/entity/entity-mapper/entity-mapper.service";
import { EntityRegistry } from "../../../../core/entity/database-entity.decorator";
import { ScreenWidthObserver } from "../../../../utils/media/screen-size-observer.service";
import { FilterService } from "../../../../core/filter/filter.service";

@DynamicComponent("HealthCheckup")
@Component({
Expand All @@ -18,12 +18,7 @@ import { ScreenWidthObserver } from "../../../../utils/media/screen-size-observe
imports: [EntitiesTableComponent],
standalone: true,
})
export class HealthCheckupComponent
extends RelatedEntitiesComponent<HealthCheck>
implements OnInit
{
@Input() entity: Child;
property = "child";
export class HealthCheckupComponent extends RelatedEntitiesComponent<HealthCheck> {
entityCtr = HealthCheck;

/**
Expand All @@ -49,8 +44,9 @@ export class HealthCheckupComponent
entityMapper: EntityMapperService,
entityRegistry: EntityRegistry,
screenWidthObserver: ScreenWidthObserver,
filterService: FilterService,
) {
super(entityMapper, entityRegistry, screenWidthObserver);
super(entityMapper, entityRegistry, screenWidthObserver, filterService);
}

private getBMI(healthCheck: HealthCheck): string {
Expand All @@ -62,26 +58,10 @@ export class HealthCheckupComponent
}
}

override createNewRecordFactory() {
return () => {
const newHC = new HealthCheck();

newHC.date = new Date();
newHC.child = this.entity.getId();

return newHC;
};
}

/**
* implements the health check loading from the children service and is called in the onInit()
*/
override async initData() {
this.data = (
await this.childrenService.getHealthChecksOfChild(this.entity.getId())
).sort(
(a, b) =>
(b.date ? b.date.valueOf() : 0) - (a.date ? a.date.valueOf() : 0),
);
override getData() {
return this.childrenService.getHealthChecksOfChild(this.entity.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { DatabaseEntity } from "../../../../core/entity/database-entity.decorato
import { DatabaseField } from "../../../../core/entity/database-field.decorator";
import { WarningLevel } from "../../../warning-level";
import { Child } from "../../model/child";
import { PLACEHOLDERS } from "../../../../core/entity/schema/entity-schema-field";

/**
* Model Class for the Health Checks that are taken for a Child.
Expand All @@ -44,6 +45,7 @@ export class HealthCheck extends Entity {
@DatabaseField({
label: $localize`:Label for date of a health check:Date`,
anonymize: "retain-anonymized",
defaultValue: PLACEHOLDERS.NOW,
})
date: Date;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
import { NotesRelatedToEntityComponent } from "./notes-related-to-entity.component";
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from "@angular/core/testing";
import { ChildrenService } from "../../children/children.service";
import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
import { Note } from "../model/note";
import { Child } from "../../children/model/child";
import { MockedTestingModule } from "../../../utils/mocked-testing.module";
import { Entity } from "../../../core/entity/model/entity";
import { School } from "../../schools/model/school";
import { User } from "../../../core/user/user";
import moment from "moment";
import { ChildSchoolRelation } from "../../children/model/childSchoolRelation";
import { DatabaseEntity } from "../../../core/entity/database-entity.decorator";
import { DatabaseField } from "../../../core/entity/database-field.decorator";
import { User } from "../../../core/user/user";
import { ChildSchoolRelation } from "../../children/model/childSchoolRelation";

describe("NotesRelatedToEntityComponent", () => {
let component: NotesRelatedToEntityComponent;
let fixture: ComponentFixture<NotesRelatedToEntityComponent>;

let mockChildrenService: jasmine.SpyObj<ChildrenService>;

beforeEach(waitForAsync(() => {
mockChildrenService = jasmine.createSpyObj(["getNotesRelatedTo"]);
mockChildrenService.getNotesRelatedTo.and.resolveTo([]);
TestBed.configureTestingModule({
imports: [NotesRelatedToEntityComponent, MockedTestingModule.withState()],
providers: [{ provide: ChildrenService, useValue: mockChildrenService }],
}).compileComponents();
}));

beforeEach(async () => {
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(NotesRelatedToEntityComponent);
component = fixture.componentInstance;
component.entity = new Child("1");
fixture.detectChanges();
});
}));

it("should create", () => {
expect(component).toBeTruthy();
Expand All @@ -56,32 +43,36 @@ describe("NotesRelatedToEntityComponent", () => {
expect(note.getColorForId).toHaveBeenCalledWith(entity.getId());
});

it("should create a new note and fill it with the appropriate initial value", () => {
it("should create a new note and fill it with the appropriate initial value", async () => {
let entity: Entity = new Child();
component.entity = entity;
component.ngOnInit();
let note = component.generateNewRecordFactory()();
component.filter = undefined;
await component.ngOnInit();
let note = component.createNewRecordFactory()();
expect(note.children).toEqual([entity.getId()]);

entity = new School();
component.entity = entity;
component.ngOnInit();
note = component.generateNewRecordFactory()();
component.filter = undefined;
await component.ngOnInit();
note = component.createNewRecordFactory()();
expect(note.schools).toEqual([entity.getId()]);

entity = new User();
component.entity = entity;
component.ngOnInit();
note = component.generateNewRecordFactory()();
component.filter = undefined;
await component.ngOnInit();
note = component.createNewRecordFactory()();
expect(note.relatedEntities).toEqual([entity.getId(true)]);

entity = new ChildSchoolRelation();
entity["childId"] = "someChild";
entity["schoolId"] = "someSchool";
component.entity = entity;
component.ngOnInit();
note = component.generateNewRecordFactory()();
expect(note.relatedEntities).toContain(entity.getId(true));
component.filter = undefined;
await component.ngOnInit();
note = component.createNewRecordFactory()();
expect(note.relatedEntities).toEqual([entity.getId(true)]);
expect(note.children).toEqual(["someChild"]);
expect(note.schools).toEqual(["someSchool"]);
});
Expand Down Expand Up @@ -110,39 +101,23 @@ describe("NotesRelatedToEntityComponent", () => {
];
customEntity.childrenLink = "child-without-prefix";

const schemaBefore = Note.schema.get("relatedEntities").additional;
Note.schema.get("relatedEntities").additional = [
Child.ENTITY_TYPE,
EntityWithRelations.ENTITY_TYPE,
];
component.entity = customEntity;
component.ngOnInit();

const newNote = component.generateNewRecordFactory()();
const newNote = component.createNewRecordFactory()();

expect(newNote.relatedEntities).toContain(customEntity.getId(true));
expect(newNote.relatedEntities).toContain(customEntity.links[0]);
expect(newNote.relatedEntities).not.toContain(customEntity.links[1]);
expect(newNote.relatedEntities).toContain(
Entity.createPrefixedId(Child.ENTITY_TYPE, customEntity.childrenLink),
);
});

it("should sort notes by date", fakeAsync(() => {
// No date should come first
const n1 = new Note();
const n2 = new Note();
n2.date = moment().subtract(1, "day").toDate();
const n3 = new Note();
n3.date = moment().subtract(2, "days").toDate();
mockChildrenService.getNotesRelatedTo.and.resolveTo([n3, n2, n1]);

component.entity = new Child();
component.ngOnInit();
tick();

expect(mockChildrenService.getNotesRelatedTo).toHaveBeenCalledWith(
component.entity.getId(true),
);
expect(component.data).toEqual([n1, n2, n3]);
}));
Note.schema.get("relatedEntities").additional = schemaBefore;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { Component } from "@angular/core";
import { Note } from "../model/note";
import { NoteDetailsComponent } from "../note-details/note-details.component";
import { ChildrenService } from "../../children/children.service";
import moment from "moment";
import { FormDialogService } from "../../../core/form-dialog/form-dialog.service";
import { DynamicComponent } from "../../../core/config/dynamic-components/dynamic-component.decorator";
import { Entity } from "../../../core/entity/model/entity";
import { FilterService } from "../../../core/filter/filter.service";
import { Child } from "../../children/model/child";
import { School } from "../../schools/model/school";
import { ChildSchoolRelation } from "../../children/model/childSchoolRelation";
import { EntityDatatype } from "../../../core/basic-datatypes/entity/entity.datatype";
import { EntityArrayDatatype } from "../../../core/basic-datatypes/entity-array/entity-array.datatype";
Expand Down Expand Up @@ -46,17 +44,17 @@ export class NotesRelatedToEntityComponent extends RelatedEntitiesComponent<Note
* @param note note to get color for
*/
getColor = (note: Note) => note?.getColor();
newRecordFactory = this.generateNewRecordFactory();
newRecordFactory = this.createNewRecordFactory();

constructor(
private childrenService: ChildrenService,
private formDialog: FormDialogService,
private filterService: FilterService,
entityMapper: EntityMapperService,
entities: EntityRegistry,
screenWidthOberserver: ScreenWidthObserver,
screenWidthObserver: ScreenWidthObserver,
filterService: FilterService,
) {
super(entityMapper, entities, screenWidthOberserver);
super(entityMapper, entities, screenWidthObserver, filterService);
}

override ngOnInit() {
Expand All @@ -67,31 +65,15 @@ export class NotesRelatedToEntityComponent extends RelatedEntitiesComponent<Note
return super.ngOnInit();
}

override async initData() {
this.data = await this.childrenService
.getNotesRelatedTo(this.entity.getId(true))
.then((notes: Note[]) => {
notes.sort((a, b) => {
if (!a.date && b.date) {
// note without date should be first
return -1;
}
return moment(b.date).valueOf() - moment(a.date).valueOf();
});
return notes;
});
override getData() {
return this.childrenService.getNotesRelatedTo(this.entity.getId(true));
}

generateNewRecordFactory() {
override createNewRecordFactory() {
return () => {
const newNote = new Note(Date.now().toString());

const newNote = super.createNewRecordFactory()();
//TODO: generalize this code - possibly by only using relatedEntities to link other records here? see #1501
if (this.entity.getType() === Child.ENTITY_TYPE) {
newNote.addChild(this.entity as Child);
} else if (this.entity.getType() === School.ENTITY_TYPE) {
newNote.addSchool(this.entity as School);
} else if (this.entity.getType() === ChildSchoolRelation.ENTITY_TYPE) {
if (this.entity.getType() === ChildSchoolRelation.ENTITY_TYPE) {
newNote.addChild((this.entity as ChildSchoolRelation).childId);
newNote.addSchool((this.entity as ChildSchoolRelation).schoolId);
}
Expand All @@ -101,8 +83,6 @@ export class NotesRelatedToEntityComponent extends RelatedEntitiesComponent<Note
newNote.relatedEntities.push(e),
);

this.filterService.alignEntityWithFilter(newNote, this.filter);

return newNote;
};
}
Expand Down
Loading