From fcc3da3ad18e1da419c155d99e66b3a190699996 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 10:01:00 +0200 Subject: [PATCH 001/230] added functionality for defining a component to display a property in the entity schema and the datatypes --- src/app/core/entity/entity.ts | 9 ++++- .../entity/schema/entity-schema-datatype.ts | 7 ++++ .../core/entity/schema/entity-schema-field.ts | 8 +++++ .../schema/entity-schema.service.spec.ts | 35 +++++++++++++++++++ .../entity/schema/entity-schema.service.ts | 20 ++++++++++- 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/entity.ts index 492b78c694..d2d8307370 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/entity.ts @@ -150,10 +150,17 @@ export class Entity { /** * Get the class (Entity or the actual subclass of the instance) to call static methods on the correct class considering inheritance */ - getConstructor(): typeof Entity { + getConstructor(): EntityConstructor { return this.constructor; } + /** + * Get the entity schema of this class + */ + getSchema(): EntitySchema { + return this.getConstructor().schema; + } + /** * Returns the id of this entity. * diff --git a/src/app/core/entity/schema/entity-schema-datatype.ts b/src/app/core/entity/schema/entity-schema-datatype.ts index e523bde916..512c7dccbd 100644 --- a/src/app/core/entity/schema/entity-schema-datatype.ts +++ b/src/app/core/entity/schema/entity-schema-datatype.ts @@ -34,6 +34,13 @@ export interface EntitySchemaDatatype { */ name: string; + /** + * The default component how this datatype should be displayed in lists and forms. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + */ + displayComponent?: string; + /** * Transformation function taking a value in the format that is used in entity instances and returning the value * in the format used in database objects. diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index a24c843b12..d17e9c7720 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -58,4 +58,12 @@ export interface EntitySchemaField { * that are not part of the core datatypes and therefore not included in this core interface. */ ext?: any; + + /** + * (Optional) Define using which component this property should be displayed in lists and forms. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the default component for this datatype will be used. + */ + displayComponent?: string; } diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 1eec19a880..28a4280f01 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -19,6 +19,7 @@ import { Entity } from "../entity"; import { waitForAsync } from "@angular/core/testing"; import { EntitySchemaService } from "./entity-schema.service"; import { DatabaseField } from "../database-field.decorator"; +import { EntitySchemaDatatype } from "./entity-schema-datatype"; describe("EntitySchemaService", () => { let entitySchemaService: EntitySchemaService; @@ -190,4 +191,38 @@ describe("EntitySchemaService", () => { expect(rawData.details.month).toEqual("2020-01"); expect(rawData.details.otherStuff).toBeUndefined(); }); + + it("should return the directly defined component name for displaying and editing a property", () => { + class Test extends Entity { + @DatabaseField({ dataType: "month", displayComponent: "DisplayDate" }) + month: Date; + } + + const displayComponent = entitySchemaService.getDisplayComponent( + new Test(), + "month" + ); + + expect(displayComponent).toEqual("DisplayDate"); + }); + + it("should return the display component of the datatype if no other is defined", () => { + const testDatatype: EntitySchemaDatatype = { + name: "test-datatype", + displayComponent: "DisplayText", + transformToDatabaseFormat: () => null, + transformToObjectFormat: () => null, + }; + entitySchemaService.registerSchemaDatatype(testDatatype); + class Test extends Entity { + @DatabaseField({ dataType: "test-datatype" }) stringProperty: string; + } + + const displayComponent = entitySchemaService.getDisplayComponent( + new Test(), + "stringProperty" + ); + + expect(displayComponent).toEqual("DisplayText"); + }); }); diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index e66bba71de..69b9778b50 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -129,7 +129,7 @@ export class EntitySchemaService { public loadDataIntoEntity(entity: Entity, data: any) { data = this.transformDatabaseToEntityFormat( data, - (entity.constructor).schema + entity.getConstructor().schema ); Object.assign(entity, data); } @@ -173,4 +173,22 @@ export class EntitySchemaService { return data; } + + /** + * Get the name of the component that should display this property. + * The names will be one of the DYNAMIC_COMPONENT_MAP. + * + * @param entity The entity on which the property exists + * @param property The name of the property + * @returns the name of the component which should display this property + */ + getDisplayComponent(entity: Entity, property: string): string { + const propertySchema = entity.getSchema().get(property); + if (propertySchema.displayComponent) { + return propertySchema.displayComponent; + } else { + return this.getDatatypeOrDefault(propertySchema.dataType) + .displayComponent; + } + } } From 5adec2749e15c74ef7105319f6bbe26334284555 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 10:20:45 +0200 Subject: [PATCH 002/230] initializing default components in the entity list component --- .../entity-list/EntityListConfig.ts | 2 +- .../entity-list/entity-list.component.spec.ts | 37 +++++++++++++++++++ .../entity-list/entity-list.component.ts | 18 ++++++++- .../schema/entity-schema.service.spec.ts | 4 +- .../entity/schema/entity-schema.service.ts | 13 ++++--- 5 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/app/core/entity-components/entity-list/EntityListConfig.ts b/src/app/core/entity-components/entity-list/EntityListConfig.ts index 05566288e7..ea99aa3a4a 100644 --- a/src/app/core/entity-components/entity-list/EntityListConfig.ts +++ b/src/app/core/entity-components/entity-list/EntityListConfig.ts @@ -19,7 +19,7 @@ export class EntityListConfig { } export class ColumnConfig { - component: string; + component?: string; title: string; id: string; /** this config can be anything that the component understands to parse */ diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index d7a93c2012..42c78d1130 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -24,6 +24,7 @@ import { LoggingService } from "../../logging/logging.service"; import { BackupService } from "../../admin/services/backup.service"; import { EntityListModule } from "./entity-list.module"; import { Angulartics2Module } from "angulartics2"; +import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; describe("EntityListComponent", () => { let component: EntityListComponent; @@ -79,6 +80,7 @@ describe("EntityListComponent", () => { let mockLoggingService: jasmine.SpyObj; let mockSessionService: jasmine.SpyObj; let mockEntityMapper: jasmine.SpyObj; + let mockEntitySchemaService: jasmine.SpyObj; beforeEach( waitForAsync(() => { @@ -87,6 +89,8 @@ describe("EntityListComponent", () => { mockConfigService = jasmine.createSpyObj(["getConfig"]); mockLoggingService = jasmine.createSpyObj(["warn"]); mockEntityMapper = jasmine.createSpyObj(["save"]); + mockEntitySchemaService = jasmine.createSpyObj(["getDisplayComponent"]); + TestBed.configureTestingModule({ declarations: [EntityListComponent, ExportDataComponent], imports: [ @@ -104,6 +108,7 @@ describe("EntityListComponent", () => { { provide: EntityMapperService, useValue: mockEntityMapper }, { provide: LoggingService, useValue: mockLoggingService }, { provide: BackupService, useValue: {} }, + { provide: EntitySchemaService, useValue: mockEntitySchemaService }, ], }).compileComponents(); }) @@ -319,4 +324,36 @@ describe("EntityListComponent", () => { .map((note) => note.getId()); expect(sortedIds).toEqual(["0", "3", "1", "2"]); }); + + it("should init column components with the default display component if none is defined", () => { + component.listConfig.columns = [ + { + title: "with defined component", + id: "withDefinedComponent", + component: "predefinedComponent", + }, + { + title: "without defined component", + id: "withoutDefinedComponent", + }, + ]; + mockEntitySchemaService.getDisplayComponent.and.returnValue( + "defaultDisplayComponent" + ); + + component.ngOnChanges({ listConfig: null }); + + expect(component.columns).toEqual([ + { + title: "with defined component", + id: "withDefinedComponent", + component: "predefinedComponent", + }, + { + title: "without defined component", + id: "withoutDefinedComponent", + component: "defaultDisplayComponent", + }, + ]); + }); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 8dc3daf94e..6b610a7c99 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -41,6 +41,7 @@ import { import { LoggingService } from "../../logging/logging.service"; import { OperationType } from "../../permissions/entity-permissions.service"; import { entityListSortingAccessor } from "./sorting-accessor"; +import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; interface FilterComponentSettings { filterSettings: FilterSelection; @@ -104,7 +105,8 @@ export class EntityListComponent private media: MediaObserver, private router: Router, private activatedRoute: ActivatedRoute, - private entityMapperService: EntityMapperService + private entityMapperService: EntityMapperService, + private entitySchemaService: EntitySchemaService ) { this.paginatorKey = getUrlWithoutParams(this.router); } @@ -140,7 +142,7 @@ export class EntityListComponent ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty("listConfig")) { this.listName = this.listConfig.title; - this.columns = this.listConfig.columns; + this.initColumns(this.listConfig.columns); this.initColumnGroups(this.listConfig.columnGroup); this.filtersConfig = this.listConfig.filters || []; this.displayColumnGroup(this.defaultColumnGroup); @@ -152,6 +154,18 @@ export class EntityListComponent this.loadUrlParams(); } + private initColumns(columns: ColumnConfig[]) { + this.columns = columns.map((column) => { + if (!column.component) { + column.component = this.entitySchemaService.getDisplayComponent( + this.entityConstructor, + column.id + ); + } + return column; + }); + } + private initDefaultSort() { if (!this.sort || this.sort.active) { // do not overwrite existing sort diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 28a4280f01..9748eb51af 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -199,7 +199,7 @@ describe("EntitySchemaService", () => { } const displayComponent = entitySchemaService.getDisplayComponent( - new Test(), + Test, "month" ); @@ -219,7 +219,7 @@ describe("EntitySchemaService", () => { } const displayComponent = entitySchemaService.getDisplayComponent( - new Test(), + Test, "stringProperty" ); diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index 69b9778b50..b3c8039604 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity, EntityConstructor } from "../entity"; import { EntitySchemaDatatype } from "./entity-schema-datatype"; import { Injectable } from "@angular/core"; import { defaultEntitySchemaDatatype } from "../schema-datatypes/datatype-default"; @@ -178,12 +178,15 @@ export class EntitySchemaService { * Get the name of the component that should display this property. * The names will be one of the DYNAMIC_COMPONENT_MAP. * - * @param entity The entity on which the property exists + * @param entityClass The class of the entity on which the property exists * @param property The name of the property - * @returns the name of the component which should display this property + * @returns string The name of the component which should display this property */ - getDisplayComponent(entity: Entity, property: string): string { - const propertySchema = entity.getSchema().get(property); + getDisplayComponent( + entityClass: EntityConstructor, + property: string + ): string { + const propertySchema = entityClass.schema.get(property); if (propertySchema.displayComponent) { return propertySchema.displayComponent; } else { From 1faccd5e2705ba5c0ebdfbc61f4cb6ba56c1de68 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 11:00:28 +0200 Subject: [PATCH 003/230] changed children list config to use default components --- src/app/core/config/config-fix.ts | 19 ------------------- .../configurable-enum-datatype.ts | 1 + .../schema-datatypes/datatype-date-only.ts | 1 + .../entity/schema-datatypes/datatype-date.ts | 1 + .../schema-datatypes/datatype-default.ts | 1 + .../schema-datatypes/datatype-string.ts | 1 + .../entity/schema/entity-schema.service.ts | 2 +- 7 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index deef7427ed..252d8e668a 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -450,7 +450,6 @@ export const defaultConfig = { "title": "Children List", "columns": [ { - "component": "DisplayText", "title": "PN", "id": "projectNumber" }, @@ -465,12 +464,10 @@ export const defaultConfig = { "id": "age" }, { - "component": "DisplayDate", "title": "DoB", "id": "dateOfBirth" }, { - "component": "DisplayText", "title": "Gender", "id": "gender" }, @@ -508,82 +505,66 @@ export const defaultConfig = { "id": "center" }, { - "component": "DisplayText", "title": "Status", "id": "status" }, { - "component": "DisplayDate", "title": "Admission", "id": "admissionDate" }, { - "component": "DisplayText", "title": "Mother Tongue", "id": "motherTongue" }, { - "component": "DisplayConfigurableEnum", "title": "Aadhar", "id": "has_aadhar" }, { - "component": "DisplayConfigurableEnum", "title": "Bank Account", "id": "has_bankAccount" }, { - "component": "DisplayConfigurableEnum", "title": "Kanyashree", "id": "has_kanyashree" }, { - "component": "DisplayConfigurableEnum", "title": "Ration Card", "id": "has_rationCard" }, { - "component": "DisplayConfigurableEnum", "title": "BPL Card", "id": "has_BplCard" }, { - "component": "DisplayText", "title": "Vaccination Status", "id": "health_vaccinationStatus" }, { - "component": "DisplayText", "title": "Blood Group", "id": "health_bloodGroup" }, { - "component": "DisplayText", "title": "Eye Status", "id": "health_eyeHealthStatus" }, { - "component": "DisplayDate", "title": "Last Eye Check-Up", "id": "health_lastEyeCheckup" }, { - "component": "DisplayDate", "title": "Last Dental Check-Up", "id": "health_lastDentalCheckup" }, { - "component": "DisplayDate", "title": "Last ENT Check-Up", "id": "health_lastENTCheckup" }, { - "component": "DisplayDate", "title": "Last Vitamin D", "id": "health_lastVitaminD" }, { - "component": "DisplayDate", "title": "Last De-Worming", "id": "health_lastDeworming" }, diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index d2a02e300b..0563268552 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -10,6 +10,7 @@ import { EntitySchemaField } from "../../entity/schema/entity-schema-field"; export class ConfigurableEnumDatatype implements EntitySchemaDatatype { public readonly name = "configurable-enum"; + public readonly displayComponent = "DisplayConfigurableEnum"; constructor(private configService: ConfigService) {} diff --git a/src/app/core/entity/schema-datatypes/datatype-date-only.ts b/src/app/core/entity/schema-datatypes/datatype-date-only.ts index 1ef688f7c5..b2616a6623 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date-only.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date-only.ts @@ -28,6 +28,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const dateOnlyEntitySchemaDatatype: EntitySchemaDatatype = { name: "date-only", + displayComponent: "DisplayDate", transformToDatabaseFormat: (value: Date) => { if (!(value instanceof Date)) { diff --git a/src/app/core/entity/schema-datatypes/datatype-date.ts b/src/app/core/entity/schema-datatypes/datatype-date.ts index 86a989df8b..ca2aabd9ec 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date.ts @@ -29,6 +29,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const dateEntitySchemaDatatype: EntitySchemaDatatype = { name: "date", + displayComponent: "DisplayDate", transformToDatabaseFormat: (value: Date) => { // TODO: should date format be saved as date object or as string "YYYY-mm-dd"? diff --git a/src/app/core/entity/schema-datatypes/datatype-default.ts b/src/app/core/entity/schema-datatypes/datatype-default.ts index 20d0dceffc..b91f038038 100644 --- a/src/app/core/entity/schema-datatypes/datatype-default.ts +++ b/src/app/core/entity/schema-datatypes/datatype-default.ts @@ -24,6 +24,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const defaultEntitySchemaDatatype: EntitySchemaDatatype = { name: "any", + displayComponent: "DisplayText", transformToDatabaseFormat: (value) => { return value; diff --git a/src/app/core/entity/schema-datatypes/datatype-string.ts b/src/app/core/entity/schema-datatypes/datatype-string.ts index 61f018d2ff..c87474c036 100644 --- a/src/app/core/entity/schema-datatypes/datatype-string.ts +++ b/src/app/core/entity/schema-datatypes/datatype-string.ts @@ -31,6 +31,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const stringEntitySchemaDatatype: EntitySchemaDatatype = { name: "string", + displayComponent: "DisplayText", transformToDatabaseFormat: (value) => { return String(value); diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index b3c8039604..65368497fd 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -129,7 +129,7 @@ export class EntitySchemaService { public loadDataIntoEntity(entity: Entity, data: any) { data = this.transformDatabaseToEntityFormat( data, - entity.getConstructor().schema + (entity.constructor).schema ); Object.assign(entity, data); } From d34f09f7839f3bbd880fecddcf54c114f1af5adf Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 11:39:42 +0200 Subject: [PATCH 004/230] a lable is automatically added through schema if none is present --- .../entity-list/EntityListConfig.ts | 2 +- .../entity-list/entity-list.component.spec.ts | 31 +++++++++++++++++++ .../entity-list/entity-list.component.ts | 3 ++ .../core/entity/schema/entity-schema-field.ts | 5 +++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/app/core/entity-components/entity-list/EntityListConfig.ts b/src/app/core/entity-components/entity-list/EntityListConfig.ts index ea99aa3a4a..481e4291ea 100644 --- a/src/app/core/entity-components/entity-list/EntityListConfig.ts +++ b/src/app/core/entity-components/entity-list/EntityListConfig.ts @@ -20,7 +20,7 @@ export class EntityListConfig { export class ColumnConfig { component?: string; - title: string; + title?: string; id: string; /** this config can be anything that the component understands to parse */ config?: any; diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 42c78d1130..c7bbb936b2 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -25,6 +25,7 @@ import { BackupService } from "../../admin/services/backup.service"; import { EntityListModule } from "./entity-list.module"; import { Angulartics2Module } from "angulartics2"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; +import { DatabaseField } from "../../entity/database-field.decorator"; describe("EntityListComponent", () => { let component: EntityListComponent; @@ -356,4 +357,34 @@ describe("EntityListComponent", () => { }, ]); }); + + it("should use the label of the attribute schema if not label is present", () => { + class Test extends Entity { + @DatabaseField({ label: "Test Property" }) testProperty: string; + } + component.entityConstructor = Test; + component.listConfig.columns = [ + { id: "testProperty", component: "DisplayText" }, + { + id: "anotherProperty", + title: "Predefined Title", + component: "DisplayText", + }, + ]; + + component.ngOnChanges({ listConfig: null }); + + expect(component.columns).toEqual([ + { + title: "Test Property", + id: "testProperty", + component: "DisplayText", + }, + { + title: "Predefined Title", + id: "anotherProperty", + component: "DisplayText", + }, + ]); + }); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 6b610a7c99..d8318ea589 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -162,6 +162,9 @@ export class EntityListComponent column.id ); } + if (!column.title) { + column.title = this.entityConstructor.schema.get(column.id).label; + } return column; }); } diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index d17e9c7720..225f91df1f 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -66,4 +66,9 @@ export interface EntitySchemaField { * If nothing is defined, the default component for this datatype will be used. */ displayComponent?: string; + + /** + * A label which explains this value in a human readable way + */ + label?: string; } From 7239ace0bb84862e6069b414853da48820e8ea87 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 11:54:45 +0200 Subject: [PATCH 005/230] added labels to the child entity and removed labels from children list config --- .../child-dev-project/children/model/child.ts | 12 ++--- src/app/core/config/config-fix.ts | 45 ++++++------------- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 291d3934e1..6ebf4d77f2 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -42,15 +42,15 @@ export class Child extends Entity { } @DatabaseField() name: string; - @DatabaseField() projectNumber: string; // project number - @DatabaseField({ dataType: "date-only" }) dateOfBirth: Date; - @DatabaseField() motherTongue: string = ""; - @DatabaseField({ dataType: "string" }) gender: Gender; // M or F + @DatabaseField({ label: "PN" }) projectNumber: string; // project number + @DatabaseField({ dataType: "date-only", label: "DoB" }) dateOfBirth: Date; + @DatabaseField({ label: "Mother Tongue" }) motherTongue: string = ""; + @DatabaseField({ dataType: "string", label: "Gender" }) gender: Gender; // M or F @DatabaseField() religion: string = ""; @DatabaseField() center: Center; - @DatabaseField() admissionDate: Date; - @DatabaseField() status: string = ""; + @DatabaseField({ label: "Admission" }) admissionDate: Date; + @DatabaseField({ label: "Status" }) status: string = ""; @DatabaseField() dropoutDate: Date; @DatabaseField() dropoutType: string; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 252d8e668a..2faf2e8619 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -450,7 +450,6 @@ export const defaultConfig = { "title": "Children List", "columns": [ { - "title": "PN", "id": "projectNumber" }, { @@ -464,11 +463,9 @@ export const defaultConfig = { "id": "age" }, { - "title": "DoB", "id": "dateOfBirth" }, { - "title": "Gender", "id": "gender" }, { @@ -505,67 +502,51 @@ export const defaultConfig = { "id": "center" }, { - "title": "Status", "id": "status" }, { - "title": "Admission", "id": "admissionDate" }, { - "title": "Mother Tongue", "id": "motherTongue" }, { - "title": "Aadhar", "id": "has_aadhar" }, { - "title": "Bank Account", "id": "has_bankAccount" }, { - "title": "Kanyashree", "id": "has_kanyashree" }, { - "title": "Ration Card", "id": "has_rationCard" }, { - "title": "BPL Card", "id": "has_BplCard" }, { - "title": "Vaccination Status", "id": "health_vaccinationStatus" }, { - "title": "Blood Group", "id": "health_bloodGroup" }, { - "title": "Eye Status", "id": "health_eyeHealthStatus" }, { - "title": "Last Eye Check-Up", "id": "health_lastEyeCheckup" }, { - "title": "Last Dental Check-Up", "id": "health_lastDentalCheckup" }, { - "title": "Last ENT Check-Up", "id": "health_lastENTCheckup" }, { - "title": "Last Vitamin D", "id": "health_lastVitaminD" }, { - "title": "Last De-Worming", "id": "health_lastDeworming" }, { @@ -1171,19 +1152,19 @@ export const defaultConfig = { {"name": "guardianName", "schema": { "dataType": "string" } }, {"name": "preferredTimeForGuardianMeeting", "schema": { "dataType": "string" } }, {"name": "center", "schema": { "dataType": "configurable-enum", "innerDataType": "center" }}, - {"name": "has_aadhar", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status" } }, - {"name": "has_bankAccount", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status" } }, - {"name": "has_kanyashree", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status" } }, - {"name": "has_rationCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status" } }, - {"name": "has_BplCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status" } }, - {"name": "health_vaccinationStatus", "schema": { "dataType": "string" } }, - {"name": "health_bloodGroup", "schema": { "dataType": "string" } }, - {"name": "health_lastDentalCheckup", "schema": { "dataType": "Date" } }, - {"name": "health_lastEyeCheckup", "schema": { "dataType": "Date" } }, - {"name": "health_lastENTCheckup", "schema": { "dataType": "Date" } }, - {"name": "health_eyeHealthStatus", "schema": { "dataType": "string" } }, - {"name": "health_lastVitaminD", "schema": { "dataType": "Date" } }, - {"name": "health_lastDeworming", "schema": { "dataType": "Date" } } + {"name": "has_aadhar", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Aadhar" } }, + {"name": "has_bankAccount", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Bank Account" } }, + {"name": "has_kanyashree", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Kanyashree" } }, + {"name": "has_rationCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Ration Card" } }, + {"name": "has_BplCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "BPL Card" } }, + {"name": "health_vaccinationStatus", "schema": { "dataType": "string", label: "Vaccination Status" } }, + {"name": "health_bloodGroup", "schema": { "dataType": "string", label: "Blood Group" } }, + {"name": "health_lastDentalCheckup", "schema": { "dataType": "Date", label: "Last Dental Check-Up" } }, + {"name": "health_lastEyeCheckup", "schema": { "dataType": "Date", label: "Last Eye Check-Up" } }, + {"name": "health_lastENTCheckup", "schema": { "dataType": "Date", label: "Last ENT Check-Up" } }, + {"name": "health_eyeHealthStatus", "schema": { "dataType": "string", label: "Eye Status" } }, + {"name": "health_lastVitaminD", "schema": { "dataType": "Date", label: "Last Vitamin D" } }, + {"name": "health_lastDeworming", "schema": { "dataType": "Date", label: "Last De-Worming" } } ] }, "entity:School": { From d86d8c8d05c1de74e042b4781d55292ee09bbdff Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 12:34:45 +0200 Subject: [PATCH 006/230] automatically initializing columns that are only defined in the columnGroups --- .../entity-list/entity-list.component.spec.ts | 88 +++++++++---------- .../entity-list/entity-list.component.ts | 47 +++++++--- 2 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index c7bbb936b2..a1618823bf 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -35,6 +35,7 @@ describe("EntityListComponent", () => { columns: [ { component: "DisplayText", title: "PN", id: "projectNumber" }, { component: "ChildBlock", title: "Name", id: "name" }, + { component: "DisplayText", title: "Age", id: "age" }, { component: "DisplayDate", title: "DoB", id: "dateOfBirth" }, { component: "DisplayText", title: "Gender", id: "gender" }, { component: "DisplayText", title: "Class", id: "schoolClass" }, @@ -326,65 +327,62 @@ describe("EntityListComponent", () => { expect(sortedIds).toEqual(["0", "3", "1", "2"]); }); - it("should init column components with the default display component if none is defined", () => { - component.listConfig.columns = [ - { - title: "with defined component", - id: "withDefinedComponent", - component: "predefinedComponent", - }, - { - title: "without defined component", - id: "withoutDefinedComponent", - }, - ]; - mockEntitySchemaService.getDisplayComponent.and.returnValue( - "defaultDisplayComponent" - ); - - component.ngOnChanges({ listConfig: null }); - - expect(component.columns).toEqual([ - { - title: "with defined component", - id: "withDefinedComponent", - component: "predefinedComponent", - }, - { - title: "without defined component", - id: "withoutDefinedComponent", - component: "defaultDisplayComponent", - }, - ]); - }); - - it("should use the label of the attribute schema if not label is present", () => { + it("should add and initialize columns which are only mentioned in the columnGroups", () => { class Test extends Entity { @DatabaseField({ label: "Test Property" }) testProperty: string; } component.entityConstructor = Test; + mockEntitySchemaService.getDisplayComponent.and.returnValue("DisplayText"); component.listConfig.columns = [ - { id: "testProperty", component: "DisplayText" }, { - id: "anotherProperty", + id: "anotherColumn", title: "Predefined Title", - component: "DisplayText", + component: "DisplayDate", }, ]; + component.listConfig.columnGroup = { + groups: [ + { name: "One", columns: ["anotherColumn"] }, + { name: "Both", columns: ["testProperty", "anotherColumn"] }, + ], + }; component.ngOnChanges({ listConfig: null }); - expect(component.columns).toEqual([ - { - title: "Test Property", - id: "testProperty", - component: "DisplayText", - }, + expect(component.columns).toEqual( + jasmine.arrayWithExactContents([ + { + title: "Test Property", + id: "testProperty", + component: "DisplayText", + }, + { + title: "Predefined Title", + id: "anotherColumn", + component: "DisplayDate", + }, + ]) + ); + }); + + it("should log an error when the column definition can not be initialized", () => { + component.listConfig.columns = [ { + id: "correctColumn", title: "Predefined Title", - id: "anotherProperty", - component: "DisplayText", + component: "DisplayDate", }, - ]); + ]; + component.listConfig.columnGroup = { + groups: [ + { + name: "Invalid Group", + columns: ["correctColumn", "notExistentColumn"], + }, + ], + }; + + expect(() => component.ngOnChanges({ listConfig: null })).toThrowError(); + expect(mockLoggingService.warn).toHaveBeenCalled(); }); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index d8318ea589..9994f01c56 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -24,7 +24,7 @@ import { GroupConfig, PrebuiltFilterConfig, } from "./EntityListConfig"; -import { Entity } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/entity"; import { FilterSelection, FilterSelectionOption, @@ -66,7 +66,7 @@ export class EntityListComponent implements OnChanges, OnInit, AfterViewInit { @Input() entityList: T[] = []; @Input() listConfig: EntityListConfig; - @Input() entityConstructor: typeof Entity; + @Input() entityConstructor: EntityConstructor; @Output() elementClick = new EventEmitter(); @Output() addNewClick = new EventEmitter(); @@ -142,7 +142,7 @@ export class EntityListComponent ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty("listConfig")) { this.listName = this.listConfig.title; - this.initColumns(this.listConfig.columns); + this.initColumns(); this.initColumnGroups(this.listConfig.columnGroup); this.filtersConfig = this.listConfig.filters || []; this.displayColumnGroup(this.defaultColumnGroup); @@ -154,21 +154,42 @@ export class EntityListComponent this.loadUrlParams(); } - private initColumns(columns: ColumnConfig[]) { - this.columns = columns.map((column) => { - if (!column.component) { - column.component = this.entitySchemaService.getDisplayComponent( - this.entityConstructor, - column.id - ); + private initColumns() { + const columns = this.listConfig.columns; + + const uniqueColumnIds = new Set(); + this.listConfig.columnGroup.groups.forEach((group) => + group.columns.forEach((column) => uniqueColumnIds.add(column)) + ); + uniqueColumnIds.forEach((columnId) => { + if (!columns.some((column) => column.id === columnId)) { + columns.push({ id: columnId }); } - if (!column.title) { - column.title = this.entityConstructor.schema.get(column.id).label; + }); + + this.columns = columns.map((column) => { + try { + return this.createColumnDefinitions(column); + } catch (e) { + this.loggingService.warn(`Could not initialize column ${column.id}`); + throw e; } - return column; }); } + private createColumnDefinitions(column: ColumnConfig): ColumnConfig { + if (!column.component) { + column.component = this.entitySchemaService.getDisplayComponent( + this.entityConstructor, + column.id + ); + } + if (!column.title) { + column.title = this.entityConstructor.schema.get(column.id).label; + } + return column; + } + private initDefaultSort() { if (!this.sort || this.sort.active) { // do not overwrite existing sort From 419c3c92e1fa34bcad258eb3f5e89153d5cd7373 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 12:45:26 +0200 Subject: [PATCH 007/230] fixed sideeffects --- .../entity-list/entity-list.component.spec.ts | 50 +++++++++++-------- .../entity-list/entity-list.component.ts | 4 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index a1618823bf..a9caeae080 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -333,18 +333,21 @@ describe("EntityListComponent", () => { } component.entityConstructor = Test; mockEntitySchemaService.getDisplayComponent.and.returnValue("DisplayText"); - component.listConfig.columns = [ - { - id: "anotherColumn", - title: "Predefined Title", - component: "DisplayDate", - }, - ]; - component.listConfig.columnGroup = { - groups: [ - { name: "One", columns: ["anotherColumn"] }, - { name: "Both", columns: ["testProperty", "anotherColumn"] }, + component.listConfig = { + title: "", + columns: [ + { + id: "anotherColumn", + title: "Predefined Title", + component: "DisplayDate", + }, ], + columnGroup: { + groups: [ + { name: "One", columns: ["anotherColumn"] }, + { name: "Both", columns: ["testProperty", "anotherColumn"] }, + ], + }, }; component.ngOnChanges({ listConfig: null }); @@ -366,20 +369,23 @@ describe("EntityListComponent", () => { }); it("should log an error when the column definition can not be initialized", () => { - component.listConfig.columns = [ - { - id: "correctColumn", - title: "Predefined Title", - component: "DisplayDate", - }, - ]; - component.listConfig.columnGroup = { - groups: [ + component.listConfig = { + title: "", + columns: [ { - name: "Invalid Group", - columns: ["correctColumn", "notExistentColumn"], + id: "correctColumn", + title: "Predefined Title", + component: "DisplayDate", }, ], + columnGroup: { + groups: [ + { + name: "Invalid Group", + columns: ["correctColumn", "notExistentColumn"], + }, + ], + }, }; expect(() => component.ngOnChanges({ listConfig: null })).toThrowError(); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 9994f01c56..0f6419dfba 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -155,10 +155,10 @@ export class EntityListComponent } private initColumns() { - const columns = this.listConfig.columns; + const columns = this.listConfig.columns || []; const uniqueColumnIds = new Set(); - this.listConfig.columnGroup.groups.forEach((group) => + this.listConfig?.columnGroup?.groups?.forEach((group) => group.columns.forEach((column) => uniqueColumnIds.add(column)) ); uniqueColumnIds.forEach((columnId) => { From 25b051e31ec8ef46b48703cd17e7bc6dcfacf883 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 13 May 2021 12:57:35 +0200 Subject: [PATCH 008/230] finished childrenList config to use information from schema --- .../child-dev-project/children/model/child.ts | 7 +- src/app/core/config/config-fix.ts | 66 +------------------ 2 files changed, 8 insertions(+), 65 deletions(-) diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 6ebf4d77f2..e09010bd7a 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -48,7 +48,12 @@ export class Child extends Entity { @DatabaseField({ dataType: "string", label: "Gender" }) gender: Gender; // M or F @DatabaseField() religion: string = ""; - @DatabaseField() center: Center; + @DatabaseField({ + dataType: "configurable-enum", + innerDataType: "center", + label: "Center", + }) + center: Center; @DatabaseField({ label: "Admission" }) admissionDate: Date; @DatabaseField({ label: "Status" }) status: string = ""; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 2faf2e8619..5895380be4 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -449,9 +449,6 @@ export const defaultConfig = { "config": { "title": "Children List", "columns": [ - { - "id": "projectNumber" - }, { "component": "ChildBlock", "title": "Name", @@ -462,12 +459,6 @@ export const defaultConfig = { "title": "Age", "id": "age" }, - { - "id": "dateOfBirth" - }, - { - "id": "gender" - }, { "component": "DisplayText", "title": "Class", @@ -496,64 +487,12 @@ export const defaultConfig = { }, "noSorting": true }, - { - "component": "DisplayConfigurableEnum", - "title": "Center", - "id": "center" - }, - { - "id": "status" - }, - { - "id": "admissionDate" - }, - { - "id": "motherTongue" - }, - { - "id": "has_aadhar" - }, - { - "id": "has_bankAccount" - }, - { - "id": "has_kanyashree" - }, - { - "id": "has_rationCard" - }, - { - "id": "has_BplCard" - }, - { - "id": "health_vaccinationStatus" - }, - { - "id": "health_bloodGroup" - }, - { - "id": "health_eyeHealthStatus" - }, - { - "id": "health_lastEyeCheckup" - }, - { - "id": "health_lastDentalCheckup" - }, - { - "id": "health_lastENTCheckup" - }, - { - "id": "health_lastVitaminD" - }, - { - "id": "health_lastDeworming" - }, { "component": "BmiBlock", "title": "BMI", "id": "health_BMI", - "noSorting": true} + "noSorting": true + } ], "columnGroup": { "default": "School Info", @@ -1151,7 +1090,6 @@ export const defaultConfig = { {"name": "phone", "schema": { "dataType": "string" } }, {"name": "guardianName", "schema": { "dataType": "string" } }, {"name": "preferredTimeForGuardianMeeting", "schema": { "dataType": "string" } }, - {"name": "center", "schema": { "dataType": "configurable-enum", "innerDataType": "center" }}, {"name": "has_aadhar", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Aadhar" } }, {"name": "has_bankAccount", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Bank Account" } }, {"name": "has_kanyashree", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Kanyashree" } }, From 8846898d70d546b5e27a1d7b20dbac29e121dbc6 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 07:58:32 +0200 Subject: [PATCH 009/230] refactored some names --- .../configurable-enum-datatype.ts | 2 +- .../entity-details/form/form.component.html | 2 +- .../entity-details/form/form.component.ts | 21 ++++++++++------ .../entity-list/entity-list.component.spec.ts | 4 +-- .../entity-list/entity-list.component.ts | 2 +- .../schema-datatypes/datatype-date-only.ts | 2 +- .../entity/schema-datatypes/datatype-date.ts | 2 +- .../schema-datatypes/datatype-default.ts | 2 +- .../schema-datatypes/datatype-string.ts | 2 +- .../entity/schema/entity-schema-datatype.ts | 4 ++- .../core/entity/schema/entity-schema-field.ts | 4 ++- .../schema/entity-schema.service.spec.ts | 25 +++++++++++++------ .../entity/schema/entity-schema.service.ts | 16 +++++++----- 13 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index 0563268552..2b13e5c791 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -10,7 +10,7 @@ import { EntitySchemaField } from "../../entity/schema/entity-schema-field"; export class ConfigurableEnumDatatype implements EntitySchemaDatatype { public readonly name = "configurable-enum"; - public readonly displayComponent = "DisplayConfigurableEnum"; + public readonly viewComponent = "DisplayConfigurableEnum"; constructor(private configService: ConfigService) {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index eb4078246a..744804db8a 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -5,7 +5,7 @@ fxLayout.md="row wrap" fxLayout.sm="row wrap" > -
+
@@ -134,10 +143,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { }); } - private initForm(): void { - this.form = this.fb.group(this.buildFormConfig()); - } - private checkFormValidity(): boolean { // errors regarding invalid fields wont be displayed unless marked as touched this.form.markAllAsTouched(); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index a9caeae080..bcb9568b7a 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -91,7 +91,7 @@ describe("EntityListComponent", () => { mockConfigService = jasmine.createSpyObj(["getConfig"]); mockLoggingService = jasmine.createSpyObj(["warn"]); mockEntityMapper = jasmine.createSpyObj(["save"]); - mockEntitySchemaService = jasmine.createSpyObj(["getDisplayComponent"]); + mockEntitySchemaService = jasmine.createSpyObj(["getComponent"]); TestBed.configureTestingModule({ declarations: [EntityListComponent, ExportDataComponent], @@ -332,7 +332,7 @@ describe("EntityListComponent", () => { @DatabaseField({ label: "Test Property" }) testProperty: string; } component.entityConstructor = Test; - mockEntitySchemaService.getDisplayComponent.and.returnValue("DisplayText"); + mockEntitySchemaService.getComponent.and.returnValue("DisplayText"); component.listConfig = { title: "", columns: [ diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 0f6419dfba..b7354bf0a5 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -179,7 +179,7 @@ export class EntityListComponent private createColumnDefinitions(column: ColumnConfig): ColumnConfig { if (!column.component) { - column.component = this.entitySchemaService.getDisplayComponent( + column.component = this.entitySchemaService.getComponent( this.entityConstructor, column.id ); diff --git a/src/app/core/entity/schema-datatypes/datatype-date-only.ts b/src/app/core/entity/schema-datatypes/datatype-date-only.ts index b2616a6623..7d5488814d 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date-only.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date-only.ts @@ -28,7 +28,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const dateOnlyEntitySchemaDatatype: EntitySchemaDatatype = { name: "date-only", - displayComponent: "DisplayDate", + viewComponent: "DisplayDate", transformToDatabaseFormat: (value: Date) => { if (!(value instanceof Date)) { diff --git a/src/app/core/entity/schema-datatypes/datatype-date.ts b/src/app/core/entity/schema-datatypes/datatype-date.ts index ca2aabd9ec..3790014757 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date.ts @@ -29,7 +29,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const dateEntitySchemaDatatype: EntitySchemaDatatype = { name: "date", - displayComponent: "DisplayDate", + viewComponent: "DisplayDate", transformToDatabaseFormat: (value: Date) => { // TODO: should date format be saved as date object or as string "YYYY-mm-dd"? diff --git a/src/app/core/entity/schema-datatypes/datatype-default.ts b/src/app/core/entity/schema-datatypes/datatype-default.ts index b91f038038..f0b41a63c7 100644 --- a/src/app/core/entity/schema-datatypes/datatype-default.ts +++ b/src/app/core/entity/schema-datatypes/datatype-default.ts @@ -24,7 +24,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const defaultEntitySchemaDatatype: EntitySchemaDatatype = { name: "any", - displayComponent: "DisplayText", + viewComponent: "DisplayText", transformToDatabaseFormat: (value) => { return value; diff --git a/src/app/core/entity/schema-datatypes/datatype-string.ts b/src/app/core/entity/schema-datatypes/datatype-string.ts index c87474c036..b2b9e4f524 100644 --- a/src/app/core/entity/schema-datatypes/datatype-string.ts +++ b/src/app/core/entity/schema-datatypes/datatype-string.ts @@ -31,7 +31,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const stringEntitySchemaDatatype: EntitySchemaDatatype = { name: "string", - displayComponent: "DisplayText", + viewComponent: "DisplayText", transformToDatabaseFormat: (value) => { return String(value); diff --git a/src/app/core/entity/schema/entity-schema-datatype.ts b/src/app/core/entity/schema/entity-schema-datatype.ts index 512c7dccbd..a7a2e0cdfb 100644 --- a/src/app/core/entity/schema/entity-schema-datatype.ts +++ b/src/app/core/entity/schema/entity-schema-datatype.ts @@ -39,7 +39,9 @@ export interface EntitySchemaDatatype { * * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. */ - displayComponent?: string; + viewComponent?: string; + + editComponent?: string; /** * Transformation function taking a value in the format that is used in entity instances and returning the value diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index 225f91df1f..64582948ee 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -65,7 +65,9 @@ export interface EntitySchemaField { * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. * If nothing is defined, the default component for this datatype will be used. */ - displayComponent?: string; + viewComponent?: string; + + editComponent?: string; /** * A label which explains this value in a human readable way diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 9748eb51af..bd11971bc8 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -192,24 +192,35 @@ describe("EntitySchemaService", () => { expect(rawData.details.otherStuff).toBeUndefined(); }); - it("should return the directly defined component name for displaying and editing a property", () => { + it("should return the directly defined component name for viewing and editing a property", () => { class Test extends Entity { - @DatabaseField({ dataType: "month", displayComponent: "DisplayDate" }) + @DatabaseField({ + dataType: "month", + viewComponent: "DisplayDate", + editComponent: "EditDate", + }) month: Date; } - const displayComponent = entitySchemaService.getDisplayComponent( + const viewComponent = entitySchemaService.getComponent( Test, - "month" + "month", + "view" + ); + const editComponent = entitySchemaService.getComponent( + Test, + "month", + "edit" ); - expect(displayComponent).toEqual("DisplayDate"); + expect(viewComponent).toEqual("DisplayDate"); + expect(editComponent).toEqual("EditDate"); }); it("should return the display component of the datatype if no other is defined", () => { const testDatatype: EntitySchemaDatatype = { name: "test-datatype", - displayComponent: "DisplayText", + viewComponent: "DisplayText", transformToDatabaseFormat: () => null, transformToObjectFormat: () => null, }; @@ -218,7 +229,7 @@ describe("EntitySchemaService", () => { @DatabaseField({ dataType: "test-datatype" }) stringProperty: string; } - const displayComponent = entitySchemaService.getDisplayComponent( + const displayComponent = entitySchemaService.getComponent( Test, "stringProperty" ); diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index 65368497fd..f6d14319ee 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -180,18 +180,22 @@ export class EntitySchemaService { * * @param entityClass The class of the entity on which the property exists * @param property The name of the property + * @param mode (Optional) The mode for which a component is required. Default is "view". * @returns string The name of the component which should display this property */ - getDisplayComponent( + getComponent( entityClass: EntityConstructor, - property: string + property: string, + mode: "view" | "edit" = "view" ): string { const propertySchema = entityClass.schema.get(property); - if (propertySchema.displayComponent) { - return propertySchema.displayComponent; + if (propertySchema.viewComponent) { + return mode === "view" + ? propertySchema.viewComponent + : propertySchema.editComponent; } else { - return this.getDatatypeOrDefault(propertySchema.dataType) - .displayComponent; + const datatype = this.getDatatypeOrDefault(propertySchema.dataType); + return mode === "view" ? datatype.viewComponent : datatype.editComponent; } } } From ad6f5d634c76c66f5cf57381d91b89dda45aca93 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 08:39:43 +0200 Subject: [PATCH 010/230] form component adds additional information from schemas --- .../entity-details/EntityDetailsConfig.ts | 8 +-- .../entity-details.component.spec.ts | 7 +- .../entity-details/form/FormConfig.ts | 12 ++-- .../form/form.component.spec.ts | 70 +++++++++++++++---- .../entity-details/form/form.component.ts | 16 ++++- 5 files changed, 85 insertions(+), 28 deletions(-) diff --git a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts index 709016a12c..e107a813bf 100644 --- a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts +++ b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts @@ -1,23 +1,23 @@ import { Entity } from "../../entity/entity"; -export class EntityDetailsConfig { +export interface EntityDetailsConfig { icon: string; entity: string; panels: Panel[]; } -export class Panel { +export interface Panel { title: string; components: PanelComponent[]; } -export class PanelComponent { +export interface PanelComponent { title: string; component: string; config?: PanelConfig; } -export class PanelConfig { +export interface PanelConfig { entity: Entity; creatingNew?: boolean; config?: any; diff --git a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts index d2b8e5e4fc..ced3c63a05 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts @@ -11,14 +11,13 @@ import { MatNativeDateModule } from "@angular/material/core"; import { ActivatedRoute, Router } from "@angular/router"; import { RouterTestingModule } from "@angular/router/testing"; import { MatSnackBar } from "@angular/material/snack-bar"; -import { PanelConfig, EntityDetailsConfig } from "./EntityDetailsConfig"; +import { PanelConfig } from "./EntityDetailsConfig"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { User } from "../../user/user"; import { SessionService } from "../../session/session-service/session.service"; import { ChildrenModule } from "../../../child-dev-project/children/children.module"; import { Child } from "../../../child-dev-project/children/model/child"; import { ConfirmationDialogService } from "../../confirmation-dialog/confirmation-dialog.service"; -import { FormConfig } from "./form/FormConfig"; import { EntityPermissionsService } from "../../permissions/entity-permissions.service"; import { ChildrenService } from "../../../child-dev-project/children/children.service"; @@ -28,7 +27,7 @@ describe("EntityDetailsComponent", () => { let routeObserver: Subscriber; - const routeConfig: EntityDetailsConfig = { + const routeConfig = { icon: "child", entity: "Child", panels: [ @@ -38,7 +37,7 @@ describe("EntityDetailsComponent", () => { { title: "", component: "Form", - config: { cols: [[]] } as FormConfig, + config: { cols: [[]] }, }, ], }, diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-details/form/FormConfig.ts index 2923c01635..925bc921e1 100644 --- a/src/app/core/entity-components/entity-details/form/FormConfig.ts +++ b/src/app/core/entity-components/entity-details/form/FormConfig.ts @@ -1,15 +1,13 @@ -import { PanelConfig } from "../EntityDetailsConfig"; - -export class FormConfig extends PanelConfig { +export interface FormConfig { cols: FormFieldConfig[][]; } -export class FormFieldConfig { +export interface FormFieldConfig { /** * The input type for the form. * Available options: "photo", "text", "textarea", "checkbox", "age", "select", "configurable-enum-select", "datepicker" */ - input: string; + input?: string; /** * The id of the entity which should be accessed @@ -19,13 +17,13 @@ export class FormFieldConfig { /** * A placeholder or description of the expected input */ - placeholder: string; + placeholder?: string; /** * If required is set to "true", the form cannot be saved if the field is empty. * Default to false */ - required: boolean = false; + required?: boolean; /** * The options in case `input="select"` is used. diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index f963cf538c..b6f796da65 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -19,31 +19,38 @@ import { ChildPhotoService } from "../../../../child-dev-project/children/child- import { AlertService } from "../../../alerts/alert.service"; import { Child } from "../../../../child-dev-project/children/model/child"; import { ConfigService } from "../../../config/config.service"; +import { Entity } from "../../../entity/entity"; +import { DatabaseField } from "../../../entity/database-field.decorator"; +import { EntitySchemaService } from "../../../entity/schema/entity-schema.service"; describe("FormComponent", () => { let component: FormComponent; let fixture: ComponentFixture; - const mockChildPhotoService: jasmine.SpyObj = jasmine.createSpyObj( - "mockChildPhotoService", - ["canSetImage", "setImage", "getImage"] - ); - - const mockSessionService: jasmine.SpyObj = jasmine.createSpyObj( - "mockSessionService", - { getCurrentUser: new User("test-user") } - ); + let mockChildPhotoService: jasmine.SpyObj; + let mockSessionService: jasmine.SpyObj; let mockConfigService: jasmine.SpyObj; let mockEntityMapper: jasmine.SpyObj; + let mockEntitySchemaService: jasmine.SpyObj; const testChild = new Child("Test Name"); beforeEach( waitForAsync(() => { - mockConfigService = jasmine.createSpyObj("mockConfigService", [ - "getConfig", + mockChildPhotoService = jasmine.createSpyObj([ + "canSetImage", + "setImage", + "getImage", + ]); + mockSessionService = jasmine.createSpyObj({ + getCurrentUser: new User("test-user"), + }); + mockConfigService = jasmine.createSpyObj(["getConfig"]); + mockEntityMapper = jasmine.createSpyObj(["save"]); + mockEntitySchemaService = jasmine.createSpyObj([ + "getComponent", + "registerSchemaDatatype", ]); - mockEntityMapper = jasmine.createSpyObj("mockEntityMapper", ["save"]); TestBed.configureTestingModule({ declarations: [FormComponent], @@ -57,6 +64,7 @@ describe("FormComponent", () => { { provide: ChildPhotoService, useValue: mockChildPhotoService }, { provide: SessionService, useValue: mockSessionService }, { provide: ConfigService, useValue: mockConfigService }, + { provide: EntitySchemaService, useValue: mockEntitySchemaService }, ], }).compileComponents(); }) @@ -148,6 +156,44 @@ describe("FormComponent", () => { flush(); })); + + it("should add column definitions from property schema", () => { + class Test extends Entity { + @DatabaseField({ label: "Predefined label" }) propertyField: string; + } + mockEntitySchemaService.getComponent.and.returnValue("PredefinedComponent"); + + component.onInitFromDynamicConfig({ + entity: new Test(), + config: { + cols: [ + [ + { + id: "fieldWithDefinition", + input: "SomeComponent", + placeholder: "Field with definition", + }, + { id: "propertyField" }, + ], + ], + }, + }); + + expect(component.columns).toEqual([ + [ + { + id: "fieldWithDefinition", + input: "SomeComponent", + placeholder: "Field with definition", + }, + { + id: "propertyField", + input: "PredefinedComponent", + placeholder: "Predefined label", + }, + ], + ]); + }); }); export const testConfig = { diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 47dd7012f5..f4951bfe96 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -115,7 +115,21 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { } private initForm(): void { - this.columns = this.config.cols; + this.columns = this.config.cols.map((column) => + column.map((row) => { + if (!row.input) { + row.input = this.entitySchemaService.getComponent( + this.entity.getConstructor(), + row.id, + "edit" + ); + } + if (!row.placeholder) { + row.placeholder = this.entity.getSchema().get(row.id).label; + } + return row; + }) + ); this.form = this.fb.group(this.buildFormConfig()); } From 948341f752f7e23a5c0b720a9bcbc5c901d7bf2f Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 08:53:20 +0200 Subject: [PATCH 011/230] refactored getComponent function --- .../entity-details/form/form.component.ts | 6 ++--- .../entity-list/entity-list.component.spec.ts | 1 + .../entity-list/entity-list.component.ts | 7 +++--- .../schema/entity-schema.service.spec.ts | 10 ++++---- .../entity/schema/entity-schema.service.ts | 23 ++++++++----------- 5 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index f4951bfe96..8e225dde95 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -117,15 +117,15 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { private initForm(): void { this.columns = this.config.cols.map((column) => column.map((row) => { + const propertySchema = this.entity.getSchema().get(row.id); if (!row.input) { row.input = this.entitySchemaService.getComponent( - this.entity.getConstructor(), - row.id, + propertySchema, "edit" ); } if (!row.placeholder) { - row.placeholder = this.entity.getSchema().get(row.id).label; + row.placeholder = propertySchema.label; } return row; }) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index bcb9568b7a..0e0fd3ed3e 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -120,6 +120,7 @@ describe("EntityListComponent", () => { fixture = TestBed.createComponent(EntityListComponent); component = fixture.componentInstance; component.listConfig = testConfig; + component.entityConstructor = Child; component.ngOnChanges({ entityList: new SimpleChange(null, component.entityList, false), listConfig: new SimpleChange(null, component.listConfig, false), diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index b7354bf0a5..30f904d398 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -178,14 +178,15 @@ export class EntityListComponent } private createColumnDefinitions(column: ColumnConfig): ColumnConfig { + const propertySchema = this.entityConstructor.schema.get(column.id); if (!column.component) { column.component = this.entitySchemaService.getComponent( - this.entityConstructor, - column.id + propertySchema, + "view" ); } if (!column.title) { - column.title = this.entityConstructor.schema.get(column.id).label; + column.title = propertySchema.label; } return column; } diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index bd11971bc8..b7278b440f 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -203,13 +203,11 @@ describe("EntitySchemaService", () => { } const viewComponent = entitySchemaService.getComponent( - Test, - "month", + Test.schema.get("month"), "view" ); const editComponent = entitySchemaService.getComponent( - Test, - "month", + Test.schema.get("month"), "edit" ); @@ -230,8 +228,8 @@ describe("EntitySchemaService", () => { } const displayComponent = entitySchemaService.getComponent( - Test, - "stringProperty" + Test.schema.get("stringProperty"), + "view" ); expect(displayComponent).toEqual("DisplayText"); diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index f6d14319ee..d0eb12b1fd 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity, EntityConstructor } from "../entity"; +import { Entity } from "../entity"; import { EntitySchemaDatatype } from "./entity-schema-datatype"; import { Injectable } from "@angular/core"; import { defaultEntitySchemaDatatype } from "../schema-datatypes/datatype-default"; @@ -178,24 +178,19 @@ export class EntitySchemaService { * Get the name of the component that should display this property. * The names will be one of the DYNAMIC_COMPONENT_MAP. * - * @param entityClass The class of the entity on which the property exists - * @param property The name of the property + * @param propertySchema The schema definition of the attribute for which a component should be get * @param mode (Optional) The mode for which a component is required. Default is "view". * @returns string The name of the component which should display this property */ getComponent( - entityClass: EntityConstructor, - property: string, + propertySchema: EntitySchemaField, mode: "view" | "edit" = "view" ): string { - const propertySchema = entityClass.schema.get(property); - if (propertySchema.viewComponent) { - return mode === "view" - ? propertySchema.viewComponent - : propertySchema.editComponent; - } else { - const datatype = this.getDatatypeOrDefault(propertySchema.dataType); - return mode === "view" ? datatype.viewComponent : datatype.editComponent; - } + const componentAttribute = + mode === "view" ? "viewComponent" : "editComponent"; + return ( + propertySchema[componentAttribute] || + this.getDatatypeOrDefault(propertySchema.dataType)[componentAttribute] + ); } } From ed945b98c0921210d676a689f601f877d1e3a5a3 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 09:34:42 +0200 Subject: [PATCH 012/230] cleaned up from component --- .../entity-details/form/form.component.html | 66 +++++++++---------- .../entity-details/form/form.stories.ts | 39 ++++++----- .../core/permissions/permissions.module.ts | 1 + 3 files changed, 55 insertions(+), 51 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 744804db8a..dc47a5db6f 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -118,42 +118,38 @@
-
- - - - {{ row.placeholder }} - - - - {{ o }} - - - -
+ + + + {{ row.placeholder }} + + + + {{ o }} + + + -
- - - - {{ row.placeholder }} - - - - {{ o.label }} - - - -
+ + + + {{ row.placeholder }} + + + + {{ o.label }} + + + false }, + useValue: { userIsPermitted: () => true }, }, ], }), @@ -41,6 +41,13 @@ export default { const testConfig = { cols: [ + [ + { + input: "photo", + id: "photoFile", + placeholder: "Photo Filename", + }, + ], [ { input: "text", @@ -48,6 +55,16 @@ const testConfig = { placeholder: "Name", required: true, }, + { + input: "textarea", + id: "additionalInfo", + placeholder: "Additional information", + }, + { + input: "checkbox", + id: "active", + placeholder: "Is active", + }, { input: "select", id: "health_vaccinationStatus", @@ -62,27 +79,16 @@ const testConfig = { ], [ { - input: "select", - id: "health_eyeHealthStatus", - placeholder: "Eye Status", - options: ["Good", "Has Glasses", "Needs Glasses", "Needs Checkup"], - }, - ], - [ - { - input: "text", - id: "health_bloodGroup", - placeholder: "Blood Group", + input: "configurable-enum-select", + id: "has_rationCard", + placeholder: "Ration Card Status", + enumId: "document-status", }, - ], - [ { input: "datepicker", id: "health_lastDentalCheckup", placeholder: "Last Dental Check-Up", }, - ], - [ { input: "age", id: "dateOfBirth", @@ -101,4 +107,5 @@ export const Primary = Template.bind({}); Primary.args = { entity: new Child(), config: testConfig, + editing: true, }; diff --git a/src/app/core/permissions/permissions.module.ts b/src/app/core/permissions/permissions.module.ts index ccfdcc45aa..863550e705 100644 --- a/src/app/core/permissions/permissions.module.ts +++ b/src/app/core/permissions/permissions.module.ts @@ -8,5 +8,6 @@ import { MatTooltipModule } from "@angular/material/tooltip"; declarations: [DisableEntityOperationDirective, DisabledWrapperComponent], imports: [CommonModule, MatTooltipModule], exports: [DisableEntityOperationDirective], + entryComponents: [DisabledWrapperComponent], }) export class PermissionsModule {} From 60dbdac08b52110d0726972ff82cec63dcf03e2a Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 10:08:34 +0200 Subject: [PATCH 013/230] added dynamic textfield component --- .../entity-details/entity-details.module.ts | 10 +- .../entity-details/form/FormConfig.ts | 2 + .../textfield/textfield.component.html | 17 + .../textfield/textfield.component.scss | 0 .../textfield/textfield.component.spec.ts | 25 ++ .../textfield/textfield.component.ts | 24 ++ .../entity-details/form/form.component.html | 313 +++++++++--------- .../entity-details/form/form.stories.ts | 99 +++--- src/app/core/view/dynamic-components-map.ts | 2 + 9 files changed, 291 insertions(+), 201 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 147fc197f3..41a3b65a1b 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -20,9 +20,16 @@ import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { PermissionsModule } from "../../permissions/permissions.module"; +import { PhotoComponent } from "./form/edit-components/photo/photo.component"; +import { TextfieldComponent } from "./form/edit-components/textfield/textfield.component"; @NgModule({ - declarations: [EntityDetailsComponent, FormComponent], + declarations: [ + EntityDetailsComponent, + FormComponent, + PhotoComponent, + TextfieldComponent, + ], imports: [ CommonModule, ReactiveFormsModule, @@ -44,5 +51,6 @@ import { PermissionsModule } from "../../permissions/permissions.module"; ConfigurableEnumModule, PermissionsModule, ], + entryComponents: [TextfieldComponent], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-details/form/FormConfig.ts index 925bc921e1..8c779be4f2 100644 --- a/src/app/core/entity-components/entity-details/form/FormConfig.ts +++ b/src/app/core/entity-components/entity-details/form/FormConfig.ts @@ -34,4 +34,6 @@ export interface FormFieldConfig { * The id of the enum in case `input="configurable-enum-select" is used. */ enumId?: string; + + tooltip?: string; } diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html new file mode 100644 index 0000000000..b718428f05 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html @@ -0,0 +1,17 @@ + + + + + {{ placeholder }} is required + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts new file mode 100644 index 0000000000..1770d93516 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TextfieldComponent } from './textfield.component'; + +describe('TextfieldComponent', () => { + let component: TextfieldComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TextfieldComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TextfieldComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts new file mode 100644 index 0000000000..4227304201 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts @@ -0,0 +1,24 @@ +import { Component } from "@angular/core"; +import { OnInitDynamicComponent } from "../../../../../view/dynamic-components/on-init-dynamic-component.interface"; +import { AbstractControl } from "@angular/forms"; + +@Component({ + selector: "app-textfield", + templateUrl: "./textfield.component.html", + styleUrls: ["./textfield.component.scss"], +}) +export class TextfieldComponent implements OnInitDynamicComponent { + tooltip: string; + formControlName: string; + placeholder: string; + formControl: AbstractControl; + + constructor() {} + + onInitFromDynamicConfig(config: any) { + this.formControlName = config["id"]; + this.tooltip = config["tooltip"]; + this.placeholder = config["placeholder"]; + this.formControl = config["formControl"]; + } +} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index dc47a5db6f..5d34f088df 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -6,166 +6,177 @@ fxLayout.sm="row wrap" >
-
-
- child's photo + + + + + + + + + - - + + + + + + + + + + + + + + - - - - -
+ + + + + + + + + + + + + + + + + + + + - - - - - {{ row.placeholder }} is required - - + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + - {{ row.placeholder }} - + + + + + + -
- - - - - - - - - -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - {{ row.placeholder }} - - - - {{ o }} - - - + + + + + + + + + + + + + + - - - - {{ row.placeholder }} - - - - {{ o.label }} - - - + + + + + + + + + + + + + + + + + - - - - - -
+ + + + + + + + + + + + + + +
diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index e65f83d0d8..28f8d75dea 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -11,6 +11,7 @@ import { RouterTestingModule } from "@angular/router/testing"; import { User } from "../../../user/user"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { EntityPermissionsService } from "../../../permissions/entity-permissions.service"; +import { TextfieldComponent } from "./edit-components/textfield/textfield.component"; export default { title: "Core/Form", @@ -23,8 +24,8 @@ export default { BrowserAnimationsModule, ], providers: [ - { provide: EntityMapperService, useValue: {} }, - { provide: AlertService, useValue: {} }, + { provide: EntityMapperService, useValue: { save: () => null } }, + { provide: AlertService, useValue: { addDanger: () => null } }, { provide: ChildPhotoService, useValue: { canSetImage: () => true } }, { provide: SessionService, @@ -41,59 +42,59 @@ export default { const testConfig = { cols: [ + // [ + // { + // input: "photo", + // id: "photoFile", + // placeholder: "Photo Filename", + // }, + // ], [ { - input: "photo", - id: "photoFile", - placeholder: "Photo Filename", - }, - ], - [ - { - input: "text", + input: "TextfieldComponent", id: "name", placeholder: "Name", required: true, }, - { - input: "textarea", - id: "additionalInfo", - placeholder: "Additional information", - }, - { - input: "checkbox", - id: "active", - placeholder: "Is active", - }, - { - input: "select", - id: "health_vaccinationStatus", - placeholder: "Peter Status", - options: [ - "Good", - "Vaccination Due", - "Needs Checking", - "No Card/Information", - ], - }, - ], - [ - { - input: "configurable-enum-select", - id: "has_rationCard", - placeholder: "Ration Card Status", - enumId: "document-status", - }, - { - input: "datepicker", - id: "health_lastDentalCheckup", - placeholder: "Last Dental Check-Up", - }, - { - input: "age", - id: "dateOfBirth", - placeholder: "Date of Birth", - }, + // { + // input: "textarea", + // id: "additionalInfo", + // placeholder: "Additional information", + // }, + // { + // input: "checkbox", + // id: "active", + // placeholder: "Is active", + // }, + // { + // input: "select", + // id: "health_vaccinationStatus", + // placeholder: "Peter Status", + // options: [ + // "Good", + // "Vaccination Due", + // "Needs Checking", + // "No Card/Information", + // ], + // }, + // ], + // [ + // { + // input: "configurable-enum-select", + // id: "has_rationCard", + // placeholder: "Ration Card Status", + // enumId: "document-status", + // }, + // { + // input: "datepicker", + // id: "health_lastDentalCheckup", + // placeholder: "Last Dental Check-Up", + // }, + // { + // input: "age", + // id: "dateOfBirth", + // placeholder: "Date of Birth", + // }, ], ], }; diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 43029378aa..86f51198de 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -28,6 +28,7 @@ import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/d import { UsersBlockComponent } from "../user/users-block/users-block.component"; import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; +import { TextfieldComponent } from "../entity-components/entity-details/form/edit-components/textfield/textfield.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -60,4 +61,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["UserList", UserListComponent], ["DashboardShortcutWidget", DashboardShortcutWidgetComponent], ["HistoricalDataComponent", HistoricalDataComponent], + ["TextfieldComponent", TextfieldComponent], ]); From 0fbf0a8a70fb83b8bdcd81eedf16f890b2b590c3 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 16:45:11 +0200 Subject: [PATCH 014/230] refactored form component and edit components --- .../entity-details/entity-details.module.ts | 8 +++--- .../edit-configurable-enum.component.html | 1 + .../edit-configurable-enum.component.scss} | 0 .../edit-configurable-enum.component.spec.ts | 25 +++++++++++++++++++ .../edit-configurable-enum.component.ts | 15 +++++++++++ .../edit-text.component.html} | 0 .../edit-text/edit-text.component.scss | 0 .../edit-text.component.spec.ts} | 12 ++++----- .../edit-text.component.ts} | 8 +++--- .../photo/photo.component.html | 1 + .../photo/photo.component.scss | 0 .../photo/photo.component.spec.ts | 25 +++++++++++++++++++ .../edit-components/photo/photo.component.ts | 15 +++++++++++ .../entity-details/form/form.component.html | 17 ------------- .../entity-details/form/form.component.ts | 11 ++++---- .../entity-details/form/form.stories.ts | 3 +-- src/app/core/view/dynamic-components-map.ts | 6 +++-- 17 files changed, 108 insertions(+), 39 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html rename src/app/core/entity-components/entity-details/form/edit-components/{textfield/textfield.component.scss => edit-configurable-enum/edit-configurable-enum.component.scss} (100%) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts rename src/app/core/entity-components/entity-details/form/edit-components/{textfield/textfield.component.html => edit-text/edit-text.component.html} (100%) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.scss rename src/app/core/entity-components/entity-details/form/edit-components/{textfield/textfield.component.spec.ts => edit-text/edit-text.component.spec.ts} (55%) rename src/app/core/entity-components/entity-details/form/edit-components/{textfield/textfield.component.ts => edit-text/edit-text.component.ts} (75%) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 41a3b65a1b..c9cd00585c 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -21,14 +21,16 @@ import { AlertsModule } from "../../alerts/alerts.module"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { PermissionsModule } from "../../permissions/permissions.module"; import { PhotoComponent } from "./form/edit-components/photo/photo.component"; -import { TextfieldComponent } from "./form/edit-components/textfield/textfield.component"; +import { EditConfigurableEnumComponent } from "./form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.component"; @NgModule({ declarations: [ EntityDetailsComponent, FormComponent, PhotoComponent, - TextfieldComponent, + EditConfigurableEnumComponent, + EditTextComponent, ], imports: [ CommonModule, @@ -51,6 +53,6 @@ import { TextfieldComponent } from "./form/edit-components/textfield/textfield.c ConfigurableEnumModule, PermissionsModule, ], - entryComponents: [TextfieldComponent], + entryComponents: [EditTextComponent, EditConfigurableEnumComponent], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html new file mode 100644 index 0000000000..7515e90107 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html @@ -0,0 +1 @@ +

edit-configurable-enum works!

diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.scss similarity index 100% rename from src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.scss rename to src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.scss diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts new file mode 100644 index 0000000000..750e29e2cc --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditConfigurableEnumComponent } from './edit-configurable-enum.component'; + +describe('EditConfigurableEnumComponent', () => { + let component: EditConfigurableEnumComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditConfigurableEnumComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditConfigurableEnumComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts new file mode 100644 index 0000000000..1df64b50c5 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-edit-configurable-enum', + templateUrl: './edit-configurable-enum.component.html', + styleUrls: ['./edit-configurable-enum.component.scss'] +}) +export class EditConfigurableEnumComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html similarity index 100% rename from src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.html rename to src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts similarity index 55% rename from src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts rename to src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts index 1770d93516..f5d2bbe924 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { TextfieldComponent } from './textfield.component'; +import { EditTextComponent } from './edit-text.component'; -describe('TextfieldComponent', () => { - let component: TextfieldComponent; - let fixture: ComponentFixture; +describe('EditTextComponent', () => { + let component: EditTextComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TextfieldComponent ] + declarations: [ EditTextComponent ] }) .compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(TextfieldComponent); + fixture = TestBed.createComponent(EditTextComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts similarity index 75% rename from src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts rename to src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts index 4227304201..d5c651bde3 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/textfield/textfield.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts @@ -3,11 +3,11 @@ import { OnInitDynamicComponent } from "../../../../../view/dynamic-components/o import { AbstractControl } from "@angular/forms"; @Component({ - selector: "app-textfield", - templateUrl: "./textfield.component.html", - styleUrls: ["./textfield.component.scss"], + selector: "app-edit-text", + templateUrl: "./edit-text.component.html", + styleUrls: ["./edit-text.component.scss"], }) -export class TextfieldComponent implements OnInitDynamicComponent { +export class EditTextComponent implements OnInitDynamicComponent { tooltip: string; formControlName: string; placeholder: string; diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html new file mode 100644 index 0000000000..4a5f565c4c --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html @@ -0,0 +1 @@ +

photo works!

diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts new file mode 100644 index 0000000000..57e25c8412 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PhotoComponent } from './photo.component'; + +describe('PhotoComponent', () => { + let component: PhotoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PhotoComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PhotoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts new file mode 100644 index 0000000000..cbb536eeb6 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-photo', + templateUrl: './photo.component.html', + styleUrls: ['./photo.component.scss'] +}) +export class PhotoComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 5d34f088df..4d77f4c5de 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -61,23 +61,6 @@ - - - - - - - - - - - - - - - - - diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 8e225dde95..072c2bdf94 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -82,7 +82,7 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { return; } - this.assignFormValuesToEntity(this.entity, this.form); + this.assignFormValuesToEntity(); try { await this.entityMapperService.save(this.entity); this.router.navigate([getParentUrl(this.router), this.entity.getId()]); @@ -148,13 +148,14 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { return formConfig; } - private assignFormValuesToEntity(entity: Entity, form: FormGroup) { - Object.keys(form.controls).forEach((key) => { - const value = form.get(key).value; + private assignFormValuesToEntity() { + Object.keys(this.form.controls).forEach((key) => { + const value = this.form.get(key).value; if (value !== null) { - entity[key] = value; + this.entity[key] = value; } }); + console.log("entity", this.entity); } private checkFormValidity(): boolean { diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index 28f8d75dea..f027f462d2 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -11,7 +11,6 @@ import { RouterTestingModule } from "@angular/router/testing"; import { User } from "../../../user/user"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { EntityPermissionsService } from "../../../permissions/entity-permissions.service"; -import { TextfieldComponent } from "./edit-components/textfield/textfield.component"; export default { title: "Core/Form", @@ -51,7 +50,7 @@ const testConfig = { // ], [ { - input: "TextfieldComponent", + input: "EditText", id: "name", placeholder: "Name", required: true, diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 86f51198de..c74f901b34 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -28,7 +28,8 @@ import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/d import { UsersBlockComponent } from "../user/users-block/users-block.component"; import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; -import { TextfieldComponent } from "../entity-components/entity-details/form/edit-components/textfield/textfield.component"; +import { EditTextComponent } from "../entity-components/entity-details/form/edit-components/edit-text/edit-text.component"; +import { EditConfigurableEnumComponent } from "../entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -61,5 +62,6 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["UserList", UserListComponent], ["DashboardShortcutWidget", DashboardShortcutWidgetComponent], ["HistoricalDataComponent", HistoricalDataComponent], - ["TextfieldComponent", TextfieldComponent], + ["EditText", EditTextComponent], + ["EditConfigurableEnum", EditConfigurableEnumComponent], ]); From 65edf3ff3cce5c6970f797420f0e2d48ee041ff2 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 16:49:56 +0200 Subject: [PATCH 015/230] copied setup code from edit text component --- .../edit-configurable-enum.component.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts index 1df64b50c5..e9140e6de3 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,15 +1,24 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from "@angular/core"; +import { OnInitDynamicComponent } from "../../../../../view/dynamic-components/on-init-dynamic-component.interface"; +import { AbstractControl } from "@angular/forms"; @Component({ - selector: 'app-edit-configurable-enum', - templateUrl: './edit-configurable-enum.component.html', - styleUrls: ['./edit-configurable-enum.component.scss'] + selector: "app-edit-configurable-enum", + templateUrl: "./edit-configurable-enum.component.html", + styleUrls: ["./edit-configurable-enum.component.scss"], }) -export class EditConfigurableEnumComponent implements OnInit { +export class EditConfigurableEnumComponent implements OnInitDynamicComponent { + tooltip: string; + formControlName: string; + placeholder: string; + formControl: AbstractControl; - constructor() { } + constructor() {} - ngOnInit(): void { + onInitFromDynamicConfig(config: any) { + this.formControlName = config["id"]; + this.tooltip = config["tooltip"]; + this.placeholder = config["placeholder"]; + this.formControl = config["formControl"]; } - } From a79a6073922cdc24d96550699c9e94a0286a1542 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 17:17:17 +0200 Subject: [PATCH 016/230] added dynamic edit configurable enum component --- .../form/edit-components/edit-component.ts | 25 +++++++++++++++++++ .../edit-configurable-enum.component.html | 18 ++++++++++++- .../edit-configurable-enum.component.ts | 21 +++------------- .../edit-text/edit-text.component.ts | 19 ++------------ .../entity-details/form/form.component.html | 3 ++- .../entity-details/form/form.component.ts | 3 +++ .../entity-details/form/form.stories.ts | 12 ++++----- 7 files changed, 58 insertions(+), 43 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts new file mode 100644 index 0000000000..7a6be9f20e --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts @@ -0,0 +1,25 @@ +import { OnInitDynamicComponent } from "../../../../view/dynamic-components/on-init-dynamic-component.interface"; +import { AbstractControl } from "@angular/forms"; + +interface EditComponentConfig { + id: string; + tooltip?: string; + placeholder: string; + formControl: AbstractControl; + enumId?: string; +} + +export abstract class EditComponent implements OnInitDynamicComponent { + tooltip: string; + formControlName: string; + placeholder: string; + formControl: AbstractControl; + enumId: string; + onInitFromDynamicConfig(config: EditComponentConfig) { + this.formControlName = config.id; + this.tooltip = config.tooltip; + this.placeholder = config.placeholder; + this.formControl = config.formControl; + this.enumId = config.enumId; + } +} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html index 7515e90107..4dfb6d0452 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html @@ -1 +1,17 @@ -

edit-configurable-enum works!

+ + + + {{ placeholder }} + + + + {{ o.label }} + + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts index e9140e6de3..967af3e7bb 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,24 +1,9 @@ -import { Component, OnInit } from "@angular/core"; -import { OnInitDynamicComponent } from "../../../../../view/dynamic-components/on-init-dynamic-component.interface"; -import { AbstractControl } from "@angular/forms"; +import { Component } from "@angular/core"; +import { EditComponent } from "../edit-component"; @Component({ selector: "app-edit-configurable-enum", templateUrl: "./edit-configurable-enum.component.html", styleUrls: ["./edit-configurable-enum.component.scss"], }) -export class EditConfigurableEnumComponent implements OnInitDynamicComponent { - tooltip: string; - formControlName: string; - placeholder: string; - formControl: AbstractControl; - - constructor() {} - - onInitFromDynamicConfig(config: any) { - this.formControlName = config["id"]; - this.tooltip = config["tooltip"]; - this.placeholder = config["placeholder"]; - this.formControl = config["formControl"]; - } -} +export class EditConfigurableEnumComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts index d5c651bde3..e92c76e521 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts @@ -1,24 +1,9 @@ import { Component } from "@angular/core"; -import { OnInitDynamicComponent } from "../../../../../view/dynamic-components/on-init-dynamic-component.interface"; -import { AbstractControl } from "@angular/forms"; +import { EditComponent } from "../edit-component"; @Component({ selector: "app-edit-text", templateUrl: "./edit-text.component.html", styleUrls: ["./edit-text.component.scss"], }) -export class EditTextComponent implements OnInitDynamicComponent { - tooltip: string; - formControlName: string; - placeholder: string; - formControl: AbstractControl; - - constructor() {} - - onInitFromDynamicConfig(config: any) { - this.formControlName = config["id"]; - this.tooltip = config["tooltip"]; - this.placeholder = config["placeholder"]; - this.formControl = config["formControl"]; - } -} +export class EditTextComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 4d77f4c5de..f0ed413ec9 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -12,7 +12,8 @@ id: row.id, placeholder: row.placeholder, tooltip: row.tooltip, - formControl: form.get(row.id) + formControl: form.get(row.id), + enumId: row.enumId } }" > diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 072c2bdf94..c3f40e2647 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -127,6 +127,9 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { if (!row.placeholder) { row.placeholder = propertySchema.label; } + if (!row.enumId) { + row.enumId = propertySchema.innerDataType; + } return row; }) ); diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index f027f462d2..c78d17c762 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -78,12 +78,12 @@ const testConfig = { // }, // ], // [ - // { - // input: "configurable-enum-select", - // id: "has_rationCard", - // placeholder: "Ration Card Status", - // enumId: "document-status", - // }, + { + input: "EditConfigurableEnum", + id: "has_rationCard", + placeholder: "Ration Card Status", + enumId: "document-status", + }, // { // input: "datepicker", // id: "health_lastDentalCheckup", From 9af5468a68e2cfa95826d76e348a7302df761d2a Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 18:53:59 +0200 Subject: [PATCH 017/230] refactored the config that is passed between form and edit components --- .../form/edit-components/edit-component.ts | 20 +++++++++++-------- .../entity-details/form/form.component.html | 16 +++++++-------- .../entity-details/form/form.component.ts | 9 +-------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts index 7a6be9f20e..d0909a01d0 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts @@ -1,12 +1,12 @@ import { OnInitDynamicComponent } from "../../../../view/dynamic-components/on-init-dynamic-component.interface"; import { AbstractControl } from "@angular/forms"; +import { FormFieldConfig } from "../FormConfig"; +import { EntitySchemaField } from "../../../../entity/schema/entity-schema-field"; interface EditComponentConfig { - id: string; - tooltip?: string; - placeholder: string; + formFieldConfig: FormFieldConfig; + propertySchema: EntitySchemaField; formControl: AbstractControl; - enumId?: string; } export abstract class EditComponent implements OnInitDynamicComponent { @@ -15,11 +15,15 @@ export abstract class EditComponent implements OnInitDynamicComponent { placeholder: string; formControl: AbstractControl; enumId: string; + onInitFromDynamicConfig(config: EditComponentConfig) { - this.formControlName = config.id; - this.tooltip = config.tooltip; - this.placeholder = config.placeholder; + this.formControlName = config.formFieldConfig.id; this.formControl = config.formControl; - this.enumId = config.enumId; + this.tooltip = + config.formFieldConfig.tooltip || config.propertySchema?.label; + this.placeholder = + config.formFieldConfig.placeholder || config.propertySchema.label; + this.enumId = + config.formFieldConfig.enumId || config.propertySchema.innerDataType; } } diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index f0ed413ec9..62e9f3690e 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -6,18 +6,18 @@ fxLayout.sm="row wrap" >
- + - + > + +
diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index c3f40e2647..4a359e2511 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -117,19 +117,12 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { private initForm(): void { this.columns = this.config.cols.map((column) => column.map((row) => { - const propertySchema = this.entity.getSchema().get(row.id); if (!row.input) { row.input = this.entitySchemaService.getComponent( - propertySchema, + this.entity.getSchema().get(row.id), "edit" ); } - if (!row.placeholder) { - row.placeholder = propertySchema.label; - } - if (!row.enumId) { - row.enumId = propertySchema.innerDataType; - } return row; }) ); From 4c82d1fbb5f1cab9aa6c2bdb906c81007ee6f949 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 18:57:42 +0200 Subject: [PATCH 018/230] fixed error messages --- .../edit-configurable-enum.component.html | 10 +++++----- .../edit-components/edit-text/edit-text.component.html | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html index 4dfb6d0452..f89040daa8 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html @@ -1,12 +1,8 @@ - {{ placeholder }} - + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html index b718428f05..42bd9954e9 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html @@ -1,8 +1,4 @@ - + {{ placeholder }} is required From 22ccdbd95188eb0eb4854e7e95903ff35a022ade Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 19:05:49 +0200 Subject: [PATCH 019/230] added component to edit dates --- .../entity-details/entity-details.module.ts | 8 ++++- .../form/edit-components/edit-component.ts | 4 +-- .../edit-date/edit-date.component.html | 13 ++++++++ .../edit-date/edit-date.component.scss | 0 .../edit-date/edit-date.component.spec.ts | 25 +++++++++++++++ .../edit-date/edit-date.component.ts | 9 ++++++ .../entity-details/form/form.component.html | 32 ------------------- .../entity-details/form/form.stories.ts | 9 +++--- src/app/core/view/dynamic-components-map.ts | 2 ++ 9 files changed, 62 insertions(+), 40 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index c9cd00585c..74a3cac442 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -23,6 +23,7 @@ import { PermissionsModule } from "../../permissions/permissions.module"; import { PhotoComponent } from "./form/edit-components/photo/photo.component"; import { EditConfigurableEnumComponent } from "./form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.component"; +import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; @NgModule({ declarations: [ @@ -31,6 +32,7 @@ import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.co PhotoComponent, EditConfigurableEnumComponent, EditTextComponent, + EditDateComponent, ], imports: [ CommonModule, @@ -53,6 +55,10 @@ import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.co ConfigurableEnumModule, PermissionsModule, ], - entryComponents: [EditTextComponent, EditConfigurableEnumComponent], + entryComponents: [ + EditTextComponent, + EditConfigurableEnumComponent, + EditDateComponent, + ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts index d0909a01d0..0ffbb5da69 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts @@ -22,8 +22,8 @@ export abstract class EditComponent implements OnInitDynamicComponent { this.tooltip = config.formFieldConfig.tooltip || config.propertySchema?.label; this.placeholder = - config.formFieldConfig.placeholder || config.propertySchema.label; + config.formFieldConfig.placeholder || config.propertySchema?.label; this.enumId = - config.formFieldConfig.enumId || config.propertySchema.innerDataType; + config.formFieldConfig.enumId || config.propertySchema?.innerDataType; } } diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.html new file mode 100644 index 0000000000..291f588490 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.html @@ -0,0 +1,13 @@ + + + + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts new file mode 100644 index 0000000000..b4fbc9953c --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditDateComponent } from './edit-date.component'; + +describe('EditDateComponent', () => { + let component: EditDateComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditDateComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditDateComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts new file mode 100644 index 0000000000..976e1748ea --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts @@ -0,0 +1,9 @@ +import { Component } from "@angular/core"; +import { EditComponent } from "../edit-component"; + +@Component({ + selector: "app-edit-date", + templateUrl: "./edit-date.component.html", + styleUrls: ["./edit-date.component.scss"], +}) +export class EditDateComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 62e9f3690e..2a78755740 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -128,39 +128,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index c78d17c762..060ae3af66 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -84,11 +84,10 @@ const testConfig = { placeholder: "Ration Card Status", enumId: "document-status", }, - // { - // input: "datepicker", - // id: "health_lastDentalCheckup", - // placeholder: "Last Dental Check-Up", - // }, + { + input: "EditDate", + id: "admissionDate", + }, // { // input: "age", // id: "dateOfBirth", diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index c74f901b34..11f19bc284 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -30,6 +30,7 @@ import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; import { EditTextComponent } from "../entity-components/entity-details/form/edit-components/edit-text/edit-text.component"; import { EditConfigurableEnumComponent } from "../entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditDateComponent } from "../entity-components/entity-details/form/edit-components/edit-date/edit-date.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -64,4 +65,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["HistoricalDataComponent", HistoricalDataComponent], ["EditText", EditTextComponent], ["EditConfigurableEnum", EditConfigurableEnumComponent], + ["EditDate", EditDateComponent], ]); From e44a2584b5b9b9b53726a85083725459d2dbd825 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 19:21:34 +0200 Subject: [PATCH 020/230] added component to edit selectables --- .../child-dev-project/children/model/child.ts | 8 +++++- .../entity-details/entity-details.module.ts | 3 +++ .../form/edit-components/edit-component.ts | 5 ++-- .../edit-configurable-enum.component.html | 4 +-- .../edit-selectable.component.html | 14 +++++++++++ .../edit-selectable.component.scss | 0 .../edit-selectable.component.spec.ts | 25 +++++++++++++++++++ .../edit-selectable.component.ts | 15 +++++++++++ .../edit-text/edit-text.component.html | 3 +-- .../entity-details/form/form.component.html | 17 ------------- .../entity-details/form/form.stories.ts | 25 ++++++++++--------- src/app/core/view/dynamic-components-map.ts | 2 ++ 12 files changed, 84 insertions(+), 37 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index e09010bd7a..e73551e862 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -45,7 +45,13 @@ export class Child extends Entity { @DatabaseField({ label: "PN" }) projectNumber: string; // project number @DatabaseField({ dataType: "date-only", label: "DoB" }) dateOfBirth: Date; @DatabaseField({ label: "Mother Tongue" }) motherTongue: string = ""; - @DatabaseField({ dataType: "string", label: "Gender" }) gender: Gender; // M or F + @DatabaseField({ + dataType: "string", + label: "Gender", + ext: ["", "M", "F"], + editComponent: "EditSelectable", + }) + gender: Gender; // M or F @DatabaseField() religion: string = ""; @DatabaseField({ diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 74a3cac442..aad941bc1e 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -24,6 +24,7 @@ import { PhotoComponent } from "./form/edit-components/photo/photo.component"; import { EditConfigurableEnumComponent } from "./form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.component"; import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; +import { EditSelectableComponent } from "./form/edit-components/edit-selectable/edit-selectable.component"; @NgModule({ declarations: [ @@ -33,6 +34,7 @@ import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.co EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, + EditSelectableComponent, ], imports: [ CommonModule, @@ -59,6 +61,7 @@ import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.co EditTextComponent, EditConfigurableEnumComponent, EditDateComponent, + EditSelectableComponent, ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts index 0ffbb5da69..dea814e475 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts @@ -3,7 +3,7 @@ import { AbstractControl } from "@angular/forms"; import { FormFieldConfig } from "../FormConfig"; import { EntitySchemaField } from "../../../../entity/schema/entity-schema-field"; -interface EditComponentConfig { +export interface EditComponentConfig { formFieldConfig: FormFieldConfig; propertySchema: EntitySchemaField; formControl: AbstractControl; @@ -19,8 +19,7 @@ export abstract class EditComponent implements OnInitDynamicComponent { onInitFromDynamicConfig(config: EditComponentConfig) { this.formControlName = config.formFieldConfig.id; this.formControl = config.formControl; - this.tooltip = - config.formFieldConfig.tooltip || config.propertySchema?.label; + this.tooltip = config.formFieldConfig.tooltip; this.placeholder = config.formFieldConfig.placeholder || config.propertySchema?.label; this.enumId = diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html index f89040daa8..94e1c893e6 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.html @@ -2,7 +2,7 @@ {{ placeholder }} - + - diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.html new file mode 100644 index 0000000000..5119b022d7 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.html @@ -0,0 +1,14 @@ + + + {{ placeholder }} + + + + {{ o }} + + + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts new file mode 100644 index 0000000000..bca0cfb2ce --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditSelectableComponent } from './edit-selectable.component'; + +describe('EditSelectableComponent', () => { + let component: EditSelectableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditSelectableComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditSelectableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts new file mode 100644 index 0000000000..74c4e20d22 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts @@ -0,0 +1,15 @@ +import { Component } from "@angular/core"; +import { EditComponent, EditComponentConfig } from "../edit-component"; + +@Component({ + selector: "app-edit-selectable", + templateUrl: "./edit-selectable.component.html", + styleUrls: ["./edit-selectable.component.scss"], +}) +export class EditSelectableComponent extends EditComponent { + options: string[]; + onInitFromDynamicConfig(config: EditComponentConfig) { + super.onInitFromDynamicConfig(config); + this.options = config.formFieldConfig.options || config.propertySchema.ext; + } +} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html index 42bd9954e9..8818bf9b50 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.html @@ -5,9 +5,8 @@ [placeholder]="placeholder" [title]="placeholder" type="text" - #inputElement /> - diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 2a78755740..d70a9510e4 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -112,23 +112,6 @@ - - - - - - - - - - - - - - - - - diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index 060ae3af66..915e165232 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -65,17 +65,18 @@ const testConfig = { // id: "active", // placeholder: "Is active", // }, - // { - // input: "select", - // id: "health_vaccinationStatus", - // placeholder: "Peter Status", - // options: [ - // "Good", - // "Vaccination Due", - // "Needs Checking", - // "No Card/Information", - // ], - // }, + { id: "gender" }, + { + input: "EditSelectable", + id: "health_vaccinationStatus", + placeholder: "Vaccination Status", + options: [ + "Good", + "Vaccination Due", + "Needs Checking", + "No Card/Information", + ], + }, // ], // [ { @@ -86,7 +87,7 @@ const testConfig = { }, { input: "EditDate", - id: "admissionDate", + id: "admissionDate" }, // { // input: "age", diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 11f19bc284..be1e31fb7d 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -31,6 +31,7 @@ import { HistoricalDataComponent } from "../../features/historical-data/historic import { EditTextComponent } from "../entity-components/entity-details/form/edit-components/edit-text/edit-text.component"; import { EditConfigurableEnumComponent } from "../entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditDateComponent } from "../entity-components/entity-details/form/edit-components/edit-date/edit-date.component"; +import { EditSelectableComponent } from "../entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -66,4 +67,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditText", EditTextComponent], ["EditConfigurableEnum", EditConfigurableEnumComponent], ["EditDate", EditDateComponent], + ["EditSelectable", EditSelectableComponent], ]); From 5678cb9a37024d64574045b5e22e1adce04ef0a9 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 19:29:11 +0200 Subject: [PATCH 021/230] added component to calcualte the age --- .../child-dev-project/children/model/child.ts | 7 ++++- .../entity-details/entity-details.module.ts | 3 ++ .../edit-age/edit-age.component.html | 28 +++++++++++++++++ .../edit-age/edit-age.component.scss | 0 .../edit-age/edit-age.component.spec.ts | 25 +++++++++++++++ .../edit-age/edit-age.component.ts | 16 ++++++++++ .../entity-details/form/form.component.html | 31 ------------------- .../entity-details/form/form.stories.ts | 10 +++--- src/app/core/view/dynamic-components-map.ts | 2 ++ 9 files changed, 84 insertions(+), 38 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index e73551e862..1cfab5767d 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -43,7 +43,12 @@ export class Child extends Entity { @DatabaseField() name: string; @DatabaseField({ label: "PN" }) projectNumber: string; // project number - @DatabaseField({ dataType: "date-only", label: "DoB" }) dateOfBirth: Date; + @DatabaseField({ + dataType: "date-only", + label: "DoB", + editComponent: "EditAge", + }) + dateOfBirth: Date; @DatabaseField({ label: "Mother Tongue" }) motherTongue: string = ""; @DatabaseField({ dataType: "string", diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index aad941bc1e..ed196c94c2 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -25,6 +25,7 @@ import { EditConfigurableEnumComponent } from "./form/edit-components/edit-confi import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.component"; import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; import { EditSelectableComponent } from "./form/edit-components/edit-selectable/edit-selectable.component"; +import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; @NgModule({ declarations: [ @@ -35,6 +36,7 @@ import { EditSelectableComponent } from "./form/edit-components/edit-selectable/ EditTextComponent, EditDateComponent, EditSelectableComponent, + EditAgeComponent, ], imports: [ CommonModule, @@ -62,6 +64,7 @@ import { EditSelectableComponent } from "./form/edit-components/edit-selectable/ EditConfigurableEnumComponent, EditDateComponent, EditSelectableComponent, + EditAgeComponent, ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.html new file mode 100644 index 0000000000..30c673ea7a --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.html @@ -0,0 +1,28 @@ +
+ + + + + + + + + +
diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts new file mode 100644 index 0000000000..3dfbde08b6 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditAgeComponent } from './edit-age.component'; + +describe('EditAgeComponent', () => { + let component: EditAgeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditAgeComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditAgeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts new file mode 100644 index 0000000000..efe566c7c9 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts @@ -0,0 +1,16 @@ +import { Component } from "@angular/core"; +import { EditComponent } from "../edit-component"; +import { calculateAge } from "../../../../../../utils/utils"; + +@Component({ + selector: "app-edit-age", + templateUrl: "./edit-age.component.html", + styleUrls: ["./edit-age.component.scss"], +}) +export class EditAgeComponent extends EditComponent { + getAge(selectedDateOfBirth: string) { + return selectedDateOfBirth + ? calculateAge(new Date(selectedDateOfBirth)) + : ""; + } +} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index d70a9510e4..dc2de17a05 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -81,37 +81,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index 915e165232..5b6d44ef77 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -87,13 +87,11 @@ const testConfig = { }, { input: "EditDate", - id: "admissionDate" + id: "admissionDate", + }, + { + id: "dateOfBirth", }, - // { - // input: "age", - // id: "dateOfBirth", - // placeholder: "Date of Birth", - // }, ], ], }; diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index be1e31fb7d..f818c7784c 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -32,6 +32,7 @@ import { EditTextComponent } from "../entity-components/entity-details/form/edit import { EditConfigurableEnumComponent } from "../entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditDateComponent } from "../entity-components/entity-details/form/edit-components/edit-date/edit-date.component"; import { EditSelectableComponent } from "../entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component"; +import { EditAgeComponent } from "../entity-components/entity-details/form/edit-components/edit-age/edit-age.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -68,4 +69,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditConfigurableEnum", EditConfigurableEnumComponent], ["EditDate", EditDateComponent], ["EditSelectable", EditSelectableComponent], + ["EditAge", EditAgeComponent], ]); From 0f7e325b3449460307b80cc481c46645000787c6 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 14 May 2021 19:33:11 +0200 Subject: [PATCH 022/230] adding component for editing booleans --- .../entity-details/entity-details.module.ts | 2 ++ .../edit-boolean/edit-boolean.component.html | 6 +++++ .../edit-boolean/edit-boolean.component.scss | 0 .../edit-boolean.component.spec.ts | 25 +++++++++++++++++++ .../edit-boolean/edit-boolean.component.ts | 9 +++++++ .../entity-details/form/form.component.html | 7 ------ 6 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index ed196c94c2..73f09da712 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -26,6 +26,7 @@ import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.co import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; import { EditSelectableComponent } from "./form/edit-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; +import { EditBooleanComponent } from './form/edit-components/edit-boolean/edit-boolean.component'; @NgModule({ declarations: [ @@ -37,6 +38,7 @@ import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.compo EditDateComponent, EditSelectableComponent, EditAgeComponent, + EditBooleanComponent, ], imports: [ CommonModule, diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html new file mode 100644 index 0000000000..71089b9164 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts new file mode 100644 index 0000000000..a3bb963dc0 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditBooleanComponent } from './edit-boolean.component'; + +describe('EditBooleanComponent', () => { + let component: EditBooleanComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditBooleanComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditBooleanComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts new file mode 100644 index 0000000000..cb2d5d83f9 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts @@ -0,0 +1,9 @@ +import { Component, OnInit } from "@angular/core"; +import { EditComponent } from "../edit-component"; + +@Component({ + selector: "app-edit-boolean", + templateUrl: "./edit-boolean.component.html", + styleUrls: ["./edit-boolean.component.scss"], +}) +export class EditBooleanComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index dc2de17a05..1177a9e8dc 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -74,13 +74,6 @@ - - - - - - - From b75138b9c3d17654d9ac5f1ad4d300f0949351f6 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 15 May 2021 09:18:10 +0200 Subject: [PATCH 023/230] implement edit boolean component --- .../entity-details/entity-details.module.ts | 3 ++- .../edit-boolean/edit-boolean.component.html | 12 ++++++------ .../entity-details/form/form.component.html | 2 +- .../entity-details/form/form.stories.ts | 10 +++++----- src/app/core/view/dynamic-components-map.ts | 2 ++ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 73f09da712..9375e1e761 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -26,7 +26,7 @@ import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.co import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; import { EditSelectableComponent } from "./form/edit-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; -import { EditBooleanComponent } from './form/edit-components/edit-boolean/edit-boolean.component'; +import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-boolean.component"; @NgModule({ declarations: [ @@ -67,6 +67,7 @@ import { EditBooleanComponent } from './form/edit-components/edit-boolean/edit-b EditDateComponent, EditSelectableComponent, EditAgeComponent, + EditBooleanComponent, ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html index 71089b9164..be62f4497d 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.html @@ -1,6 +1,6 @@ - - - - - - +
+ {{ placeholder }} + +
diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 1177a9e8dc..fe94ba80b7 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -1,4 +1,4 @@ -
+
([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -70,4 +71,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditDate", EditDateComponent], ["EditSelectable", EditSelectableComponent], ["EditAge", EditAgeComponent], + ["EditBoolean", EditBooleanComponent], ]); From 0dcbf93efdba35f0bc304044d48e42d0db186a6f Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 15 May 2021 09:22:55 +0200 Subject: [PATCH 024/230] added component to edit long texts --- .../entity-details/entity-details.module.ts | 3 +++ .../edit-boolean/edit-boolean.component.ts | 2 +- .../edit-long-text.component.html | 12 +++++++++ .../edit-long-text.component.scss | 0 .../edit-long-text.component.spec.ts | 25 +++++++++++++++++++ .../edit-long-text.component.ts | 9 +++++++ .../entity-details/form/form.component.html | 13 ---------- .../entity-details/form/form.stories.ts | 10 ++++---- src/app/core/view/dynamic-components-map.ts | 2 ++ 9 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 9375e1e761..4c79b5d8a9 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -27,6 +27,7 @@ import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.co import { EditSelectableComponent } from "./form/edit-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-boolean.component"; +import { EditLongTextComponent } from "./form/edit-components/edit-long-text/edit-long-text.component"; @NgModule({ declarations: [ @@ -39,6 +40,7 @@ import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-b EditSelectableComponent, EditAgeComponent, EditBooleanComponent, + EditLongTextComponent, ], imports: [ CommonModule, @@ -68,6 +70,7 @@ import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-b EditSelectableComponent, EditAgeComponent, EditBooleanComponent, + EditLongTextComponent, ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts index cb2d5d83f9..ea8f84b8b6 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from "@angular/core"; +import { Component } from "@angular/core"; import { EditComponent } from "../edit-component"; @Component({ diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.html new file mode 100644 index 0000000000..9dd0970486 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.html @@ -0,0 +1,12 @@ + + + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts new file mode 100644 index 0000000000..d55d04d68f --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditLongTextComponent } from './edit-long-text.component'; + +describe('EditLongTextComponent', () => { + let component: EditLongTextComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditLongTextComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditLongTextComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts new file mode 100644 index 0000000000..1834dd967f --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts @@ -0,0 +1,9 @@ +import { Component } from "@angular/core"; +import { EditComponent } from "../edit-component"; + +@Component({ + selector: "app-edit-long-text", + templateUrl: "./edit-long-text.component.html", + styleUrls: ["./edit-long-text.component.scss"], +}) +export class EditLongTextComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index fe94ba80b7..296247ca57 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -61,19 +61,6 @@ - - - - - - - - - - - - -
diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index 18f27da7a9..1d4a54ebf4 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -55,11 +55,11 @@ const testConfig = { placeholder: "Name", required: true, }, - // { - // input: "textarea", - // id: "additionalInfo", - // placeholder: "Additional information", - // }, + { + input: "EditLongText", + id: "additionalInfo", + placeholder: "Additional information", + }, { input: "EditBoolean", id: "active", diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 8848196076..feb3113267 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -34,6 +34,7 @@ import { EditDateComponent } from "../entity-components/entity-details/form/edit import { EditSelectableComponent } from "../entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "../entity-components/entity-details/form/edit-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "../entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component"; +import { EditLongTextComponent } from "../entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -72,4 +73,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditSelectable", EditSelectableComponent], ["EditAge", EditAgeComponent], ["EditBoolean", EditBooleanComponent], + ["EditLongText", EditLongTextComponent], ]); From ced5a0a6f1bce034c83ff1ed953597db4c05a0ed Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 15 May 2021 09:37:04 +0200 Subject: [PATCH 025/230] added component for editing photo files --- .../entity-details/entity-details.module.ts | 2 + .../edit-photo/edit-photo.component.html | 42 ++++++++++++++++++ .../edit-photo/edit-photo.component.scss | 0 .../edit-photo/edit-photo.component.spec.ts | 25 +++++++++++ .../edit-photo/edit-photo.component.ts | 9 ++++ .../entity-details/form/form.component.html | 43 ------------------- .../entity-details/form/form.stories.ts | 14 +++--- 7 files changed, 85 insertions(+), 50 deletions(-) create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts create mode 100644 src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 4c79b5d8a9..8aa348b414 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -28,6 +28,7 @@ import { EditSelectableComponent } from "./form/edit-components/edit-selectable/ import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "./form/edit-components/edit-long-text/edit-long-text.component"; +import { EditPhotoComponent } from './form/edit-components/edit-photo/edit-photo.component'; @NgModule({ declarations: [ @@ -41,6 +42,7 @@ import { EditLongTextComponent } from "./form/edit-components/edit-long-text/edi EditAgeComponent, EditBooleanComponent, EditLongTextComponent, + EditPhotoComponent, ], imports: [ CommonModule, diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html new file mode 100644 index 0000000000..e71d76fddd --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html @@ -0,0 +1,42 @@ +
+ child's photo + + + + + + + + +
diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts new file mode 100644 index 0000000000..ee833438b7 --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditPhotoComponent } from './edit-photo.component'; + +describe('EditPhotoComponent', () => { + let component: EditPhotoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ EditPhotoComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditPhotoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts new file mode 100644 index 0000000000..9521fb3c2d --- /dev/null +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts @@ -0,0 +1,9 @@ +import { Component } from "@angular/core"; +import { EditComponent } from "../edit-component"; + +@Component({ + selector: "app-edit-photo", + templateUrl: "./edit-photo.component.html", + styleUrls: ["./edit-photo.component.scss"], +}) +export class EditPhotoComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 296247ca57..06eac69e75 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -18,49 +18,6 @@ > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index 1d4a54ebf4..fb7a589584 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -41,13 +41,13 @@ export default { const testConfig = { cols: [ - // [ - // { - // input: "photo", - // id: "photoFile", - // placeholder: "Photo Filename", - // }, - // ], + [ + { + input: "photo", + id: "photoFile", + placeholder: "Photo Filename", + }, + ], [ { input: "EditText", From 178c66477b26d20d1435a22290b67db1d90d6132 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 06:39:44 +0200 Subject: [PATCH 026/230] added new datatype for displaying photos --- .../child-photo.service.ts | 10 ++-- .../child-photo-service/datatype-photo.ts | 52 +++++++++++++++++++ .../children/child-photo-service/photo.ts | 7 +++ .../children/children.module.ts | 8 ++- .../child-dev-project/children/model/child.ts | 6 +++ 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/app/child-dev-project/children/child-photo-service/datatype-photo.ts create mode 100644 src/app/child-dev-project/children/child-photo-service/photo.ts diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index 0d3275fe77..8f4a7c27c3 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -22,7 +22,7 @@ export class ChildPhotoService { }): Promise { let image = await this.getImageFromCloudService(child); if (!image) { - image = this.getImageFromAssets(child); + image = ChildPhotoService.getImageFromAssets(child); } return image; } @@ -50,14 +50,14 @@ export class ChildPhotoService { return image; } - private getImageFromAssets(child: { photoFile?: string }): SafeUrl { + public static getImageFromAssets(child: { photoFile?: string }): SafeUrl { if (!child.photoFile || child.photoFile.trim() === "") { return this.getDefaultImage(); } return Child.generatePhotoPath(child.photoFile); } - private getDefaultImage(): SafeUrl { + private static getDefaultImage(): SafeUrl { return "assets/child.png"; } @@ -71,7 +71,9 @@ export class ChildPhotoService { entityId: string; photoFile?: string; }): BehaviorSubject { - const resultSubject = new BehaviorSubject(this.getImageFromAssets(child)); + const resultSubject = new BehaviorSubject( + ChildPhotoService.getImageFromAssets(child) + ); this.getImageFromCloudService(child).then((photo) => { if (photo && photo !== resultSubject.value) { resultSubject.next(photo); diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts new file mode 100644 index 0000000000..240c2a2a65 --- /dev/null +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -0,0 +1,52 @@ +/* + * This file is part of ndb-core. + * + * ndb-core is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ndb-core is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ndb-core. If not, see . + */ + +import { EntitySchemaDatatype } from "../../../core/entity/schema/entity-schema-datatype"; +import { ChildPhotoService } from "./child-photo.service"; +import { EntitySchemaField } from "../../../core/entity/schema/entity-schema-field"; +import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { Entity } from "../../../core/entity/entity"; +import { Photo } from "./photo"; +import { SafeUrl } from "@angular/platform-browser"; +import { BehaviorSubject } from "rxjs"; + +/** + * Dynamically load the child's photo through the ChildPhotoService during Entity loading process. + */ +export class PhotoDatatype implements EntitySchemaDatatype { + public readonly name = "photo"; + + constructor() {} + + public transformToDatabaseFormat(value: Photo) { + return value.path; + } + + public transformToObjectFormat( + value: string, + schemaField: EntitySchemaField, + schemaService: EntitySchemaService, + parent: Entity + ): Photo { + return { + path: value, + photo: new BehaviorSubject( + ChildPhotoService.getImageFromAssets({ photoFile: value }) + ), + }; + } +} diff --git a/src/app/child-dev-project/children/child-photo-service/photo.ts b/src/app/child-dev-project/children/child-photo-service/photo.ts new file mode 100644 index 0000000000..fdaad011b3 --- /dev/null +++ b/src/app/child-dev-project/children/child-photo-service/photo.ts @@ -0,0 +1,7 @@ +import { BehaviorSubject } from "rxjs"; +import { SafeUrl } from "@angular/platform-browser"; + +export interface Photo { + path: string; + photo: BehaviorSubject; +} diff --git a/src/app/child-dev-project/children/children.module.ts b/src/app/child-dev-project/children/children.module.ts index 51f415f6b0..99e83e5e7a 100644 --- a/src/app/child-dev-project/children/children.module.ts +++ b/src/app/child-dev-project/children/children.module.ts @@ -70,6 +70,8 @@ import { PreviousTeamsComponent } from "../previous-teams/previous-teams.compone import { BmiBlockComponent } from "./children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "./children-bmi-dashboard/children-bmi-dashboard.component"; import { EntitySelectModule } from "../../core/entity-components/entity-select/entity-select.module"; +import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; +import { PhotoDatatype } from "./child-photo-service/datatype-photo"; @NgModule({ imports: [ @@ -140,4 +142,8 @@ import { EntitySelectModule } from "../../core/entity-components/entity-select/e BmiBlockComponent, ], }) -export class ChildrenModule {} +export class ChildrenModule { + constructor(entitySchemaService: EntitySchemaService) { + entitySchemaService.registerSchemaDatatype(new PhotoDatatype()); + } +} diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 291d3934e1..c8a053522a 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -23,6 +23,7 @@ import { SafeUrl } from "@angular/platform-browser"; import { BehaviorSubject } from "rxjs"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; import { calculateAge } from "../../../utils/utils"; +import { Photo } from "../child-photo-service/photo"; export type Center = ConfigurableEnumValue; @DatabaseEntity("Child") @@ -67,6 +68,11 @@ export class Child extends Entity { */ @DatabaseField() photoFile: string; + @DatabaseField({ dataType: "photo" }) specialPhoto: Photo = { + path: "1.jpg", + photo: null, + }; + @DatabaseField({ dataType: "load-child-photo", defaultValue: true }) photo: BehaviorSubject; From 57dcea130dfa5ac8784a7b781139d02da4b1ff4f Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 07:04:38 +0200 Subject: [PATCH 027/230] using new datatype for editing photos in form --- src/app/core/config/config-fix.ts | 2 +- .../entity-details/form/form.component.html | 5 +++-- .../entity-details/form/form.component.ts | 12 ++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 5c9b49f05a..d934d33b22 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -721,7 +721,7 @@ export const defaultJsonConfig = { [ { "input": "photo", - "id": "photoFile", + "id": "specialPhoto", "placeholder": "Photo Filename" } ], diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 5d1a3896dc..2f4a415adb 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -11,7 +11,7 @@
child's photo @@ -39,7 +39,8 @@ #photoFileInput matTooltip="filename for child photo uploaded by server administrator" matInput - [formControlName]="row.id" + (change)="changeFilename(photoFileInput.value, row.id)" + [value]="form.get(row.id).value?.path" [placeholder]="row.placeholder" [title]="row.placeholder" type="text" diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index e99cf1b162..7939d3b919 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -12,6 +12,8 @@ import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init import { calculateAge, getParentUrl } from "../../../../utils/utils"; import { Child } from "../../../../child-dev-project/children/model/child"; import { OperationType } from "../../../permissions/entity-permissions.service"; +import { Photo } from "../../../../child-dev-project/children/child-photo-service/photo"; +import { BehaviorSubject } from "rxjs"; /** * This component creates a form based on the passed config. @@ -110,6 +112,16 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { child.photo.next(await this.childPhotoService.getImage(child)); } + changeFilename(path: string, fromGroupID: string) { + const newValue: Photo = { + path: path, + photo: new BehaviorSubject( + ChildPhotoService.getImageFromAssets({ photoFile: path }) + ), + }; + this.form.get(fromGroupID).setValue(newValue); + } + private buildFormConfig() { const formConfig = {}; this.config.cols.forEach((c) => From 5e3bd5bbb904dd68eb2e58d776fe411c5dde61e5 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 07:43:43 +0200 Subject: [PATCH 028/230] using the new specialPhoto everywhere --- .storybook/utils/addDefaultChildPhoto.ts | 2 +- .../child-block/child-block.component.html | 4 +-- .../child-photo.service.spec.ts | 27 +++++++---------- .../child-photo.service.ts | 30 +++++++------------ .../child-photo-service/datatype-photo.ts | 2 +- .../demo-child-generator.service.ts | 6 ++-- .../children/model/child.spec.ts | 10 +++---- .../child-dev-project/children/model/child.ts | 7 ++--- .../services/child-photo-update.service.ts | 11 ++++--- .../form/form.component.spec.ts | 14 +++++---- .../entity-details/form/form.component.ts | 6 ++-- 11 files changed, 51 insertions(+), 68 deletions(-) diff --git a/.storybook/utils/addDefaultChildPhoto.ts b/.storybook/utils/addDefaultChildPhoto.ts index 5e0f190e5c..d9861cf5f8 100644 --- a/.storybook/utils/addDefaultChildPhoto.ts +++ b/.storybook/utils/addDefaultChildPhoto.ts @@ -3,5 +3,5 @@ import { BehaviorSubject } from "rxjs"; import { SafeUrl } from "@angular/platform-browser"; export function addDefaultChildPhoto(child: Child) { - child.photo = new BehaviorSubject("assets/child.png"); + child.specialPhoto.photo = new BehaviorSubject("assets/child.png"); } diff --git a/src/app/child-dev-project/children/child-block/child-block.component.html b/src/app/child-dev-project/children/child-block/child-block.component.html index 722ae8ccff..332f122b57 100644 --- a/src/app/child-dev-project/children/child-block/child-block.component.html +++ b/src/app/child-dev-project/children/child-block/child-block.component.html @@ -5,7 +5,7 @@ (click)="showDetailsPage()" [ngClass]="{ inactive: !entity.isActive, clickable: !linkDisabled }" > - + {{ entity?.name }} ({{ entity?.projectNumber }})
- +

{{ entity?.name }}

diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts index 6e308ba1b4..8de81dc487 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts @@ -14,7 +14,6 @@ describe("ChildPhotoService", () => { mockCloudFileService = jasmine.createSpyObj("mockCloudFileService", [ "isConnected", "uploadFile", - "doesFileExist", "getFile", ]); @@ -40,8 +39,7 @@ describe("ChildPhotoService", () => { const testChild = new Child("1"); const testImg = "url-encoded-img"; mockCloudFileService.isConnected.and.returnValue(true); - mockCloudFileService.doesFileExist.and.returnValue(Promise.resolve(true)); - mockCloudFileService.getFile.and.returnValue(Promise.resolve(testImg)); + mockCloudFileService.getFile.and.resolveTo(testImg); const actualImage = await service.getImage(testChild); expect(actualImage).toBe(testImg); @@ -52,26 +50,24 @@ describe("ChildPhotoService", () => { it("should getFile from assets (old pattern) if it not exists at webdav location", async () => { const testChild = new Child("1"); - testChild.photoFile = "test-photo.png"; + testChild.specialPhoto = { path: "test-photo.png", photo: null }; mockCloudFileService.isConnected.and.returnValue(true); - mockCloudFileService.doesFileExist.and.returnValue(Promise.resolve(false)); - mockCloudFileService.getFile.and.returnValue( - Promise.reject("File not found") - ); + mockCloudFileService.getFile.and.rejectWith("File not found"); const actualImage = await service.getImage(testChild); - expect(actualImage).toBe(Child.generatePhotoPath(testChild.photoFile)); + + expect(actualImage).toBe( + Child.generatePhotoPath(testChild.specialPhoto.path) + ); }); it("should getFile default if neither webdav nor assets has the file", async () => { const testChild = new Child("1"); mockCloudFileService.isConnected.and.returnValue(true); - mockCloudFileService.doesFileExist.and.returnValue(Promise.resolve(false)); - mockCloudFileService.getFile.and.returnValue( - Promise.reject("File not found") - ); + mockCloudFileService.getFile.and.rejectWith("File not found"); const actualImage = await service.getImage(testChild); + expect(actualImage).toBe(DEFAULT_IMG); }); @@ -79,8 +75,7 @@ describe("ChildPhotoService", () => { const testChild = new Child("1"); const testImg = "url-encoded-img"; mockCloudFileService.isConnected.and.returnValue(true); - mockCloudFileService.doesFileExist.and.returnValue(Promise.resolve(true)); - mockCloudFileService.getFile.and.returnValue(Promise.resolve(testImg)); + mockCloudFileService.getFile.and.resolveTo(testImg); const resultSubject = service.getImageAsyncObservable(testChild); expect(resultSubject.value).toBe(DEFAULT_IMG); @@ -108,7 +103,7 @@ describe("ChildPhotoService", () => { const childId = "1"; const testImg = { name: "test.png", data: "test-img-data" }; mockCloudFileService.isConnected.and.returnValue(true); - mockCloudFileService.uploadFile.and.returnValue(Promise.resolve(true)); + mockCloudFileService.uploadFile.and.resolveTo(true); await expectAsync(service.setImage(testImg, childId)).toBeResolved(); expect(mockCloudFileService.uploadFile).toHaveBeenCalledWith( diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index 8f4a7c27c3..cac0b6a12e 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -16,25 +16,20 @@ export class ChildPhotoService { * Creates an ArrayBuffer of the photo for that Child or the default image url. * @param child */ - public async getImage(child: { - entityId: string; - photoFile?: string; - }): Promise { - let image = await this.getImageFromCloudService(child); + public async getImage(child: Child): Promise { + let image = await this.getImageFromCloudService(child.entityId); if (!image) { - image = ChildPhotoService.getImageFromAssets(child); + image = ChildPhotoService.getImageFromAssets(child.specialPhoto?.path); } return image; } - private async getImageFromCloudService(child: { - entityId: string; - }): Promise { + private async getImageFromCloudService(entityId: string): Promise { let image; if (this.cloudFileService?.isConnected()) { const imageType = [".png", ".jpg", ".jpeg", ""]; for (const ext of imageType) { - const filepath = this.basePath + child.entityId + ext; + const filepath = this.basePath + entityId + ext; try { image = await this.cloudFileService.getFile(filepath); break; @@ -50,11 +45,11 @@ export class ChildPhotoService { return image; } - public static getImageFromAssets(child: { photoFile?: string }): SafeUrl { - if (!child.photoFile || child.photoFile.trim() === "") { + public static getImageFromAssets(photoFile: string): SafeUrl { + if (!photoFile || photoFile.trim() === "") { return this.getDefaultImage(); } - return Child.generatePhotoPath(child.photoFile); + return Child.generatePhotoPath(photoFile); } private static getDefaultImage(): SafeUrl { @@ -67,14 +62,11 @@ export class ChildPhotoService { * This allows to immediately display a proper placeholder while the loading may take some time. * @param child The Child instance for which the photo should be loaded. */ - public getImageAsyncObservable(child: { - entityId: string; - photoFile?: string; - }): BehaviorSubject { + public getImageAsyncObservable(child: Child): BehaviorSubject { const resultSubject = new BehaviorSubject( - ChildPhotoService.getImageFromAssets(child) + ChildPhotoService.getImageFromAssets(child.specialPhoto?.path) ); - this.getImageFromCloudService(child).then((photo) => { + this.getImageFromCloudService(child.entityId).then((photo) => { if (photo && photo !== resultSubject.value) { resultSubject.next(photo); } diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index 240c2a2a65..299f8438ee 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -45,7 +45,7 @@ export class PhotoDatatype implements EntitySchemaDatatype { return { path: value, photo: new BehaviorSubject( - ChildPhotoService.getImageFromAssets({ photoFile: value }) + ChildPhotoService.getImageFromAssets(value) ), }; } diff --git a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts index 44e2758f96..92364d148e 100644 --- a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts +++ b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts @@ -7,7 +7,6 @@ import { Injectable } from "@angular/core"; import { DemoDataGenerator } from "../../../core/demo-data/demo-data-generator"; import { faker } from "../../../core/demo-data/faker"; import { centersWithProbability } from "./fixtures/centers"; -import { addDefaultChildPhoto } from "../../../../../.storybook/utils/addDefaultChildPhoto"; export class DemoChildConfig { count: number; @@ -40,13 +39,16 @@ export class DemoChildGenerator extends DemoDataGenerator { child.center = faker.random.arrayElement(centersWithProbability); child.admissionDate = faker.date.past(child.age - 4); + // child.photoFile = "1.jpg"; + + child.specialPhoto = { path: "1.jpg", photo: null }; if (faker.datatype.number(100) > 90) { DemoChildGenerator.makeChildDropout(child); } // add default photo for easier use in storybook stories - addDefaultChildPhoto(child); + // addDefaultChildPhoto(child); return child; } diff --git a/src/app/child-dev-project/children/model/child.spec.ts b/src/app/child-dev-project/children/model/child.spec.ts index 965aa2a2df..05f7a7bdea 100644 --- a/src/app/child-dev-project/children/model/child.spec.ts +++ b/src/app/child-dev-project/children/model/child.spec.ts @@ -20,7 +20,7 @@ import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; import { Gender } from "./Gender"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; -import { LoadChildPhotoEntitySchemaDatatype } from "../child-photo-service/datatype-load-child-photo"; +import { PhotoDatatype } from "../child-photo-service/datatype-photo"; describe("Child", () => { const ENTITY_TYPE = "Child"; @@ -29,9 +29,7 @@ describe("Child", () => { beforeEach( waitForAsync(() => { entitySchemaService = new EntitySchemaService(); - entitySchemaService.registerSchemaDatatype( - new LoadChildPhotoEntitySchemaDatatype(null) - ); + entitySchemaService.registerSchemaDatatype(new PhotoDatatype()); }) ); @@ -63,7 +61,7 @@ describe("Child", () => { motherTongue: "Hindi", religion: "Hindu", - photoFile: "..", + specialPhoto: "..", center: { id: "alpha", label: "Alpha" }, admissionDate: new Date(), status: "Active", @@ -85,7 +83,7 @@ describe("Child", () => { entity.motherTongue = expectedData.motherTongue; entity.religion = expectedData.religion; - entity.photoFile = expectedData.photoFile; + entity.specialPhoto = { path: expectedData.specialPhoto, photo: null }; entity.center = expectedData.center; entity.admissionDate = expectedData.admissionDate; entity.status = expectedData.status; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index c8a053522a..8ba4229c12 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -68,12 +68,9 @@ export class Child extends Entity { */ @DatabaseField() photoFile: string; - @DatabaseField({ dataType: "photo" }) specialPhoto: Photo = { - path: "1.jpg", - photo: null, - }; + @DatabaseField({ dataType: "photo" }) specialPhoto: Photo; - @DatabaseField({ dataType: "load-child-photo", defaultValue: true }) + @DatabaseField({ dataType: "load-child-photo" }) photo: BehaviorSubject; get age(): number { diff --git a/src/app/core/admin/services/child-photo-update.service.ts b/src/app/core/admin/services/child-photo-update.service.ts index 7beeb08865..c4a541beb4 100644 --- a/src/app/core/admin/services/child-photo-update.service.ts +++ b/src/app/core/admin/services/child-photo-update.service.ts @@ -33,7 +33,7 @@ export class ChildPhotoUpdateService { * @param filename A guess for a likely filename that needs to be checked */ private async updatePhotoIfFileExists(child: Child, filename: string) { - if (child.photoFile && child.photoFile !== "") { + if (child.specialPhoto?.path && child.specialPhoto.path !== "") { // do not overwrite existing path return; } @@ -42,7 +42,8 @@ export class ChildPhotoUpdateService { Child.generatePhotoPath(filename) ); if (fileExists) { - child.photoFile = filename; + const currentPhoto = child.specialPhoto; + child.specialPhoto = { path: filename, photo: currentPhoto?.photo }; this.entityService.save(child); console.log( `set photoFile for Child:${child.getId()} (${ @@ -57,10 +58,8 @@ export class ChildPhotoUpdateService { await this.httpClient.get(filename).toPromise(); return true; } catch (e) { - if (e.status === 200) { - return true; - } - return false; + return e.status === 200; + } } } diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index f963cf538c..fcd23f31e2 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -106,18 +106,20 @@ describe("FormComponent", () => { it("sets a new child photo", async () => { const filename = "file/name"; + mockChildPhotoService.getImage.and.resolveTo(filename); + testChild.specialPhoto = { + path: "", + photo: new BehaviorSubject("test"), + }; + spyOn(testChild.specialPhoto.photo, "next"); - // This needs to be set in order to create an spy on this property - testChild.photo = new BehaviorSubject("test"); - - mockChildPhotoService.getImage.and.returnValue(Promise.resolve(filename)); - spyOn(testChild.photo, "next"); await component.uploadChildPhoto({ target: { files: [filename] } }); + expect(mockChildPhotoService.setImage).toHaveBeenCalledWith( filename, testChild.entityId ); - expect(testChild.photo.next).toHaveBeenCalledWith(filename); + expect(testChild.specialPhoto.photo.next).toHaveBeenCalledWith(filename); }); it("reports error when form is invalid", fakeAsync(() => { diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 7939d3b919..82206a1281 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -109,15 +109,13 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { ); // Photo does so far only work on the child entity const child: Child = this.entity as Child; - child.photo.next(await this.childPhotoService.getImage(child)); + child.specialPhoto.photo.next(await this.childPhotoService.getImage(child)); } changeFilename(path: string, fromGroupID: string) { const newValue: Photo = { path: path, - photo: new BehaviorSubject( - ChildPhotoService.getImageFromAssets({ photoFile: path }) - ), + photo: new BehaviorSubject(ChildPhotoService.getImageFromAssets(path)), }; this.form.get(fromGroupID).setValue(newValue); } From 55b3bbfdc0e402addeecee5299703a48cb4711c8 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 07:52:51 +0200 Subject: [PATCH 029/230] added tests for photo datatype --- .../datatype-photo.spec.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts new file mode 100644 index 0000000000..755e54266c --- /dev/null +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -0,0 +1,68 @@ +/* + * This file is part of ndb-core. + * + * ndb-core is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ndb-core is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ndb-core. If not, see . + */ + +import { TestBed } from "@angular/core/testing"; +import { SafeUrl } from "@angular/platform-browser"; +import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { DatabaseField } from "../../../core/entity/database-field.decorator"; +import { Entity } from "../../../core/entity/entity"; +import { ChildPhotoService } from "./child-photo.service"; +import { BehaviorSubject } from "rxjs"; +import { PhotoDatatype } from "./datatype-photo"; +import { Photo } from "./photo"; + +describe("dataType photo", () => { + let entitySchemaService: EntitySchemaService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [EntitySchemaService], + }); + + entitySchemaService = TestBed.inject( + EntitySchemaService + ); + entitySchemaService.registerSchemaDatatype(new PhotoDatatype()); + }); + + it("should only save the path of an image", () => { + class TestEntity extends Entity { + @DatabaseField({ dataType: "photo" }) photo: Photo; + } + const id = "test1"; + const entity = new TestEntity(id); + entity.photo = { path: "12345", photo: new BehaviorSubject(null) }; + + const rawData = entitySchemaService.transformEntityToDatabaseFormat(entity); + expect(rawData.photo).toEqual(entity.photo.path); + }); + + it("should set the default photo when loading", () => { + class TestEntity extends Entity { + @DatabaseField({ dataType: "photo", defaultValue: true }) + photo: Photo; + } + const defaultImg = "default-img"; + spyOn(ChildPhotoService, "getImageFromAssets").and.returnValue(defaultImg); + + const data = { _id: "someId" }; + const entity = new TestEntity(); + entitySchemaService.loadDataIntoEntity(entity, data); + + expect(entity.photo.photo.value).toEqual(defaultImg); + }); +}); From e68ad00d7d9f623f48ca33cd886d3de5a228726d Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 07:59:15 +0200 Subject: [PATCH 030/230] removed old datatypes --- .../child-photo.service.ts | 2 +- .../datatype-load-child-photo.spec.ts | 89 ------------------- .../datatype-load-child-photo.ts | 50 ----------- .../children/children.service.ts | 6 -- .../child-dev-project/children/model/child.ts | 18 ++-- 5 files changed, 7 insertions(+), 158 deletions(-) delete mode 100644 src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.spec.ts delete mode 100644 src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.ts diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index cac0b6a12e..ea081b79c7 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -52,7 +52,7 @@ export class ChildPhotoService { return Child.generatePhotoPath(photoFile); } - private static getDefaultImage(): SafeUrl { + public static getDefaultImage(): SafeUrl { return "assets/child.png"; } diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.spec.ts deleted file mode 100644 index 3f05fedb74..0000000000 --- a/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of ndb-core. - * - * ndb-core is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ndb-core is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ndb-core. If not, see . - */ - -import { fakeAsync, flush, TestBed } from "@angular/core/testing"; -import { SafeUrl } from "@angular/platform-browser"; -import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; -import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { Entity } from "../../../core/entity/entity"; -import { ChildPhotoService } from "./child-photo.service"; -import { LoadChildPhotoEntitySchemaDatatype } from "./datatype-load-child-photo"; -import { BehaviorSubject } from "rxjs"; - -describe("dataType load-child-photo", () => { - let entitySchemaService: EntitySchemaService; - let mockChildPhotoService: jasmine.SpyObj; - - beforeEach(() => { - mockChildPhotoService = jasmine.createSpyObj("mockChildPhotoService", [ - "getImageAsyncObservable", - ]); - - TestBed.configureTestingModule({ - providers: [ - EntitySchemaService, - { provide: ChildPhotoService, useValue: mockChildPhotoService }, - ], - }); - - entitySchemaService = TestBed.inject( - EntitySchemaService - ); - entitySchemaService.registerSchemaDatatype( - new LoadChildPhotoEntitySchemaDatatype(mockChildPhotoService) - ); - }); - - it("schema:load-child-photo is removed from rawData to be saved", function () { - class TestEntity extends Entity { - @DatabaseField({ dataType: "load-child-photo" }) photo: SafeUrl; - } - const id = "test1"; - const entity = new TestEntity(id); - entity.photo = "12345"; - - const rawData = entitySchemaService.transformEntityToDatabaseFormat(entity); - expect(rawData.photo).toBeUndefined(); - }); - - it("schema:load-child-photo is provided through ChildPhotoService on load", fakeAsync(() => { - class TestEntity extends Entity { - @DatabaseField({ dataType: "load-child-photo", defaultValue: true }) - photo: BehaviorSubject; - } - const id = "test1"; - const entity = new TestEntity(id); - - const defaultImg = "default-img"; - const mockCloudImg = "test-img-data"; - - const mockImgObs = new BehaviorSubject(defaultImg); - mockChildPhotoService.getImageAsyncObservable.and.returnValue(mockImgObs); - - const data = { - _id: id, - }; - entitySchemaService.loadDataIntoEntity(entity, data); - - expect(entity.photo.value).toEqual(defaultImg); - - mockImgObs.next(mockCloudImg); - mockImgObs.complete(); - flush(); - expect(entity.photo.value).toEqual(mockCloudImg); - })); -}); diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.ts deleted file mode 100644 index 4f2d49dcc8..0000000000 --- a/src/app/child-dev-project/children/child-photo-service/datatype-load-child-photo.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of ndb-core. - * - * ndb-core is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ndb-core is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ndb-core. If not, see . - */ - -import { EntitySchemaDatatype } from "../../../core/entity/schema/entity-schema-datatype"; -import { ChildPhotoService } from "./child-photo.service"; -import { EntitySchemaField } from "../../../core/entity/schema/entity-schema-field"; -import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; -import { Entity } from "../../../core/entity/entity"; - -/** - * Dynamically load the child's photo through the ChildPhotoService during Entity loading process. - */ -export class LoadChildPhotoEntitySchemaDatatype - implements EntitySchemaDatatype { - public readonly name = "load-child-photo"; - - constructor(private childPhotoService: ChildPhotoService) {} - - public transformToDatabaseFormat(value) { - return undefined; - } - - public transformToObjectFormat( - value, - schemaField: EntitySchemaField, - schemaService: EntitySchemaService, - parent: Entity - ) { - const childDummy: any = Object.assign({}, parent); - if (!childDummy.entityId) { - childDummy.entityId = Entity.extractEntityIdFromId(childDummy._id); - } - - return this.childPhotoService.getImageAsyncObservable(childDummy); - } -} diff --git a/src/app/child-dev-project/children/children.service.ts b/src/app/child-dev-project/children/children.service.ts index fb8c421f67..46289e5aa2 100644 --- a/src/app/child-dev-project/children/children.service.ts +++ b/src/app/child-dev-project/children/children.service.ts @@ -10,7 +10,6 @@ import { ChildSchoolRelation } from "./model/childSchoolRelation"; import { HealthCheck } from "../health-checkup/model/health-check"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; import { ChildPhotoService } from "./child-photo-service/child-photo.service"; -import { LoadChildPhotoEntitySchemaDatatype } from "./child-photo-service/datatype-load-child-photo"; import moment, { Moment } from "moment"; import { LoggingService } from "../../core/logging/logging.service"; import { DatabaseIndexingService } from "../../core/entity/database-indexing/database-indexing.service"; @@ -25,11 +24,6 @@ export class ChildrenService { @Optional() childPhotoService: ChildPhotoService, @Optional() private logger: LoggingService ) { - if (childPhotoService) { - this.entitySchemaService.registerSchemaDatatype( - new LoadChildPhotoEntitySchemaDatatype(childPhotoService) - ); - } this.createDatabaseIndices(); } diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 8ba4229c12..fa405becb5 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -19,11 +19,10 @@ import { Entity } from "../../../core/entity/entity"; import { Gender } from "./Gender"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { SafeUrl } from "@angular/platform-browser"; -import { BehaviorSubject } from "rxjs"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; import { calculateAge } from "../../../utils/utils"; import { Photo } from "../child-photo-service/photo"; +import { ChildPhotoService } from "../child-photo-service/child-photo.service"; export type Center = ConfigurableEnumValue; @DatabaseEntity("Child") @@ -62,16 +61,11 @@ export class Child extends Entity { /** current class (as determined through the ChildSchoolRelation docs) set during loading through ChildrenService */ schoolClass: string = ""; - /** - * Url to an image that is displayed for the child - * as a fallback option if no CloudFileService file or connection is available. - */ - @DatabaseField() photoFile: string; - - @DatabaseField({ dataType: "photo" }) specialPhoto: Photo; - - @DatabaseField({ dataType: "load-child-photo" }) - photo: BehaviorSubject; + @DatabaseField({ + dataType: "photo", + defaultValue: ChildPhotoService.getDefaultImage(), + }) + specialPhoto: Photo; get age(): number { return this.dateOfBirth ? calculateAge(this.dateOfBirth) : null; From c2f44066d5aca925b3489e1dbca0ef1337a17f1a Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:08:33 +0200 Subject: [PATCH 031/230] added migration script for old photoFile format --- .../child-photo-service/datatype-photo.spec.ts | 13 +++++++++++++ .../children/child-photo-service/datatype-photo.ts | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 755e54266c..0e48a36fa3 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -24,6 +24,7 @@ import { ChildPhotoService } from "./child-photo.service"; import { BehaviorSubject } from "rxjs"; import { PhotoDatatype } from "./datatype-photo"; import { Photo } from "./photo"; +import { Child } from "../model/child"; describe("dataType photo", () => { let entitySchemaService: EntitySchemaService; @@ -65,4 +66,16 @@ describe("dataType photo", () => { expect(entity.photo.photo.value).toEqual(defaultImg); }); + + it("should migrate a child with the old photo format", () => { + const oldFormatInDb = entitySchemaService.transformEntityToDatabaseFormat( + new Child() + ); + oldFormatInDb["photoFile"] = "oldPhotoFile.jpg"; + + const newFormatChild = new Child(); + entitySchemaService.loadDataIntoEntity(newFormatChild, oldFormatInDb); + + expect(newFormatChild.specialPhoto.path).toEqual(oldFormatInDb.photoFile); + }); }); diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index 299f8438ee..aaa6cd2385 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -42,6 +42,13 @@ export class PhotoDatatype implements EntitySchemaDatatype { schemaService: EntitySchemaService, parent: Entity ): Photo { + // Migration of old photoFile values + if ( + parent.hasOwnProperty("photoFile") && + parent["photoFile"].trim() !== "" + ) { + value = parent["photoFile"]; + } return { path: value, photo: new BehaviorSubject( From 2857d305ae026b54825845823cf633e2c3383e02 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:29:31 +0200 Subject: [PATCH 032/230] added migration service to migrate children to correct format --- .../children-migration.service.spec.ts | 52 +++++++++++++++++++ .../children-migration.service.ts | 26 ++++++++++ src/app/core/admin/admin/admin.component.html | 3 ++ src/app/core/admin/admin/admin.component.ts | 4 +- 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts create mode 100644 src/app/child-dev-project/children/child-photo-service/children-migration.service.ts diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts new file mode 100644 index 0000000000..a2cd60a77c --- /dev/null +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts @@ -0,0 +1,52 @@ +import { fakeAsync, TestBed } from "@angular/core/testing"; + +import { ChildrenMigrationService } from "./children-migration.service"; +import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; +import { Database } from "../../../core/database/database"; +import { PouchDatabase } from "../../../core/database/pouch-database"; +import { Child } from "../model/child"; + +describe("ChildrenMigrationService", () => { + let service: ChildrenMigrationService; + let database: PouchDatabase; + + beforeEach(() => { + database = PouchDatabase.createWithInMemoryDB(); + TestBed.configureTestingModule({ + providers: [{ provide: Database, useValue: database }], + }); + service = TestBed.inject(ChildrenMigrationService); + }); + + afterEach(async () => { + await database.destroy(); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); + + it("should migrate children with old format", async () => { + await database.put({ + _id: `${Child.ENTITY_TYPE}:firstChild`, + photoFile: "oldFile1.jpg", + }); + await database.put({ + _id: `${Child.ENTITY_TYPE}:secondChild`, + photoFile: "oldFile2.jpg", + }); + await database.put({ + _id: `${Child.ENTITY_TYPE}:thirdChild`, + specialPhoto: "newFormat.jpg", + }); + + await service.migratePhotoFormat(); + + const firstChild = await database.get(`${Child.ENTITY_TYPE}:firstChild`); + expect(firstChild["specialPhoto"]).toEqual("oldFile1.jpg"); + const secondChild = await database.get(`${Child.ENTITY_TYPE}:secondChild`); + expect(secondChild["specialPhoto"]).toEqual("oldFile2.jpg"); + const thirdChild = await database.get(`${Child.ENTITY_TYPE}:thirdChild`); + expect(thirdChild["specialPhoto"]).toEqual("newFormat.jpg"); + }); +}); diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts new file mode 100644 index 0000000000..822f390514 --- /dev/null +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from "@angular/core"; +import { Database } from "../../../core/database/database"; +import { Child } from "../model/child"; + +@Injectable({ + providedIn: "root", +}) +export class ChildrenMigrationService { + constructor(private database: Database) {} + + async migratePhotoFormat(): Promise { + const allChildren = await this.database.getAll(Child.ENTITY_TYPE + ":"); + allChildren.forEach((child) => { + if ( + child.hasOwnProperty("photoFile") && + child["photoFile"].trim() !== "" + ) { + const photoFile = child["photoFile"]; + delete child.photoFile; + child["specialPhoto"] = photoFile; + } + }); + + await Promise.all(allChildren.map((child) => this.database.put(child))); + } +} diff --git a/src/app/core/admin/admin/admin.component.html b/src/app/core/admin/admin/admin.component.html index 725b6b4e67..94d59a1c81 100644 --- a/src/app/core/admin/admin/admin.component.html +++ b/src/app/core/admin/admin/admin.component.html @@ -18,6 +18,9 @@

Utility Functions

+


diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index 70e65f308f..22472896a2 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -11,6 +11,7 @@ import { ConfigService } from "../../config/config.service"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { AttendanceMigrationService } from "../../../child-dev-project/attendance/attendance-migration/attendance-migration.service"; import { NotesMigrationService } from "../../../child-dev-project/notes/notes-migration/notes-migration.service"; +import { ChildrenMigrationService } from "../../../child-dev-project/children/child-photo-service/children-migration.service"; /** * Admin GUI giving administrative users different options/actions. @@ -39,7 +40,8 @@ export class AdminComponent implements OnInit { private configService: ConfigService, private entityMapper: EntityMapperService, public attendanceMigration: AttendanceMigrationService, - public notesMigration: NotesMigrationService + public notesMigration: NotesMigrationService, + public childrenMigrationService: ChildrenMigrationService ) {} ngOnInit() { From 8cb0ab1b55f4c03f9d40fe8bf9d75fb8063c5e95 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:37:13 +0200 Subject: [PATCH 033/230] making sure that default values are not saved --- .../child-photo-service/datatype-photo.spec.ts | 13 +++++++++++++ .../children/child-photo-service/datatype-photo.ts | 8 ++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 0e48a36fa3..432761af1f 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -78,4 +78,17 @@ describe("dataType photo", () => { expect(newFormatChild.specialPhoto.path).toEqual(oldFormatInDb.photoFile); }); + + it("should not safe the default value", () => { + class TestEntity extends Entity { + @DatabaseField({ dataType: "photo", defaultValue: "someFile.jpg" }) + photo: Photo; + } + + const entity = new TestEntity(); + entitySchemaService.loadDataIntoEntity(entity, {}); + const result = entitySchemaService.transformEntityToDatabaseFormat(entity); + + expect(result.photo).toBeUndefined(); + }); }); diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index aaa6cd2385..e972510e39 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -32,8 +32,12 @@ export class PhotoDatatype implements EntitySchemaDatatype { constructor() {} - public transformToDatabaseFormat(value: Photo) { - return value.path; + public transformToDatabaseFormat(value: Photo, schema: EntitySchemaField) { + if (value.path === schema.defaultValue) { + return undefined; + } else { + return value.path; + } } public transformToObjectFormat( From 47348f92d1617cbbb0b965865e37c27b1133824d Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:46:51 +0200 Subject: [PATCH 034/230] renamed photo attribute --- .storybook/utils/addDefaultChildPhoto.ts | 2 +- .../children/child-block/child-block.component.html | 4 ++-- .../child-photo-service/child-photo.service.spec.ts | 6 ++---- .../children/child-photo-service/child-photo.service.ts | 4 ++-- .../children-migration.service.spec.ts | 8 ++++---- .../child-photo-service/children-migration.service.ts | 2 +- .../children/child-photo-service/datatype-photo.spec.ts | 2 +- .../demo-data-generators/demo-child-generator.service.ts | 2 +- src/app/child-dev-project/children/model/child.spec.ts | 4 ++-- src/app/child-dev-project/children/model/child.ts | 2 +- src/app/core/admin/admin/admin.component.spec.ts | 5 +++++ src/app/core/admin/services/child-photo-update.service.ts | 7 +++---- src/app/core/config/config-fix.ts | 2 +- .../entity-details/form/form.component.spec.ts | 6 +++--- .../entity-details/form/form.component.ts | 2 +- 15 files changed, 30 insertions(+), 28 deletions(-) diff --git a/.storybook/utils/addDefaultChildPhoto.ts b/.storybook/utils/addDefaultChildPhoto.ts index d9861cf5f8..970098988a 100644 --- a/.storybook/utils/addDefaultChildPhoto.ts +++ b/.storybook/utils/addDefaultChildPhoto.ts @@ -3,5 +3,5 @@ import { BehaviorSubject } from "rxjs"; import { SafeUrl } from "@angular/platform-browser"; export function addDefaultChildPhoto(child: Child) { - child.specialPhoto.photo = new BehaviorSubject("assets/child.png"); + child.photo.photo = new BehaviorSubject("assets/child.png"); } diff --git a/src/app/child-dev-project/children/child-block/child-block.component.html b/src/app/child-dev-project/children/child-block/child-block.component.html index 332f122b57..a8c743b2f9 100644 --- a/src/app/child-dev-project/children/child-block/child-block.component.html +++ b/src/app/child-dev-project/children/child-block/child-block.component.html @@ -5,7 +5,7 @@ (click)="showDetailsPage()" [ngClass]="{ inactive: !entity.isActive, clickable: !linkDisabled }" > - + {{ entity?.name }} ({{ entity?.projectNumber }})
- +

{{ entity?.name }}

diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts index 8de81dc487..b914b9d91c 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts @@ -50,15 +50,13 @@ describe("ChildPhotoService", () => { it("should getFile from assets (old pattern) if it not exists at webdav location", async () => { const testChild = new Child("1"); - testChild.specialPhoto = { path: "test-photo.png", photo: null }; + testChild.photo = { path: "test-photo.png", photo: null }; mockCloudFileService.isConnected.and.returnValue(true); mockCloudFileService.getFile.and.rejectWith("File not found"); const actualImage = await service.getImage(testChild); - expect(actualImage).toBe( - Child.generatePhotoPath(testChild.specialPhoto.path) - ); + expect(actualImage).toBe(Child.generatePhotoPath(testChild.photo.path)); }); it("should getFile default if neither webdav nor assets has the file", async () => { diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index ea081b79c7..f990cc9818 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -19,7 +19,7 @@ export class ChildPhotoService { public async getImage(child: Child): Promise { let image = await this.getImageFromCloudService(child.entityId); if (!image) { - image = ChildPhotoService.getImageFromAssets(child.specialPhoto?.path); + image = ChildPhotoService.getImageFromAssets(child.photo?.path); } return image; } @@ -64,7 +64,7 @@ export class ChildPhotoService { */ public getImageAsyncObservable(child: Child): BehaviorSubject { const resultSubject = new BehaviorSubject( - ChildPhotoService.getImageFromAssets(child.specialPhoto?.path) + ChildPhotoService.getImageFromAssets(child.photo?.path) ); this.getImageFromCloudService(child.entityId).then((photo) => { if (photo && photo !== resultSubject.value) { diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts index a2cd60a77c..ef2ee38cfb 100644 --- a/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts @@ -37,16 +37,16 @@ describe("ChildrenMigrationService", () => { }); await database.put({ _id: `${Child.ENTITY_TYPE}:thirdChild`, - specialPhoto: "newFormat.jpg", + photo: "newFormat.jpg", }); await service.migratePhotoFormat(); const firstChild = await database.get(`${Child.ENTITY_TYPE}:firstChild`); - expect(firstChild["specialPhoto"]).toEqual("oldFile1.jpg"); + expect(firstChild["photo"]).toEqual("oldFile1.jpg"); const secondChild = await database.get(`${Child.ENTITY_TYPE}:secondChild`); - expect(secondChild["specialPhoto"]).toEqual("oldFile2.jpg"); + expect(secondChild["photo"]).toEqual("oldFile2.jpg"); const thirdChild = await database.get(`${Child.ENTITY_TYPE}:thirdChild`); - expect(thirdChild["specialPhoto"]).toEqual("newFormat.jpg"); + expect(thirdChild["photo"]).toEqual("newFormat.jpg"); }); }); diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts index 822f390514..64d88a97d9 100644 --- a/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts @@ -17,7 +17,7 @@ export class ChildrenMigrationService { ) { const photoFile = child["photoFile"]; delete child.photoFile; - child["specialPhoto"] = photoFile; + child["photo"] = photoFile; } }); diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 432761af1f..64b04691eb 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -76,7 +76,7 @@ describe("dataType photo", () => { const newFormatChild = new Child(); entitySchemaService.loadDataIntoEntity(newFormatChild, oldFormatInDb); - expect(newFormatChild.specialPhoto.path).toEqual(oldFormatInDb.photoFile); + expect(newFormatChild.photo.path).toEqual(oldFormatInDb.photoFile); }); it("should not safe the default value", () => { diff --git a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts index 92364d148e..f3c6c537f1 100644 --- a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts +++ b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts @@ -41,7 +41,7 @@ export class DemoChildGenerator extends DemoDataGenerator { child.admissionDate = faker.date.past(child.age - 4); // child.photoFile = "1.jpg"; - child.specialPhoto = { path: "1.jpg", photo: null }; + child.photo = { path: "1.jpg", photo: null }; if (faker.datatype.number(100) > 90) { DemoChildGenerator.makeChildDropout(child); diff --git a/src/app/child-dev-project/children/model/child.spec.ts b/src/app/child-dev-project/children/model/child.spec.ts index 05f7a7bdea..e978042edc 100644 --- a/src/app/child-dev-project/children/model/child.spec.ts +++ b/src/app/child-dev-project/children/model/child.spec.ts @@ -61,7 +61,7 @@ describe("Child", () => { motherTongue: "Hindi", religion: "Hindu", - specialPhoto: "..", + photo: "..", center: { id: "alpha", label: "Alpha" }, admissionDate: new Date(), status: "Active", @@ -83,7 +83,7 @@ describe("Child", () => { entity.motherTongue = expectedData.motherTongue; entity.religion = expectedData.religion; - entity.specialPhoto = { path: expectedData.specialPhoto, photo: null }; + entity.photo = { path: expectedData.photo, photo: null }; entity.center = expectedData.center; entity.admissionDate = expectedData.admissionDate; entity.status = expectedData.status; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index fa405becb5..44b6dba07a 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -65,7 +65,7 @@ export class Child extends Entity { dataType: "photo", defaultValue: ChildPhotoService.getDefaultImage(), }) - specialPhoto: Photo; + photo: Photo; get age(): number { return this.dateOfBirth ? calculateAge(this.dateOfBirth) : null; diff --git a/src/app/core/admin/admin/admin.component.spec.ts b/src/app/core/admin/admin/admin.component.spec.ts index df0b84038e..b6bffa5a5e 100644 --- a/src/app/core/admin/admin/admin.component.spec.ts +++ b/src/app/core/admin/admin/admin.component.spec.ts @@ -22,6 +22,7 @@ import { MatDialogRef } from "@angular/material/dialog"; import { SessionType } from "../../session/session-type"; import { NotesMigrationService } from "../../../child-dev-project/notes/notes-migration/notes-migration.service"; import { AttendanceMigrationService } from "../../../child-dev-project/attendance/attendance-migration/attendance-migration.service"; +import { ChildrenMigrationService } from "../../../child-dev-project/children/child-photo-service/children-migration.service"; describe("AdminComponent", () => { let component: AdminComponent; @@ -114,6 +115,10 @@ describe("AdminComponent", () => { provide: NotesMigrationService, useValue: {}, }, + { + provide: ChildrenMigrationService, + useValue: {}, + }, ], }).compileComponents(); }) diff --git a/src/app/core/admin/services/child-photo-update.service.ts b/src/app/core/admin/services/child-photo-update.service.ts index c4a541beb4..72a5974db4 100644 --- a/src/app/core/admin/services/child-photo-update.service.ts +++ b/src/app/core/admin/services/child-photo-update.service.ts @@ -33,7 +33,7 @@ export class ChildPhotoUpdateService { * @param filename A guess for a likely filename that needs to be checked */ private async updatePhotoIfFileExists(child: Child, filename: string) { - if (child.specialPhoto?.path && child.specialPhoto.path !== "") { + if (child.photo?.path && child.photo.path !== "") { // do not overwrite existing path return; } @@ -42,8 +42,8 @@ export class ChildPhotoUpdateService { Child.generatePhotoPath(filename) ); if (fileExists) { - const currentPhoto = child.specialPhoto; - child.specialPhoto = { path: filename, photo: currentPhoto?.photo }; + const currentPhoto = child.photo; + child.photo = { path: filename, photo: currentPhoto?.photo }; this.entityService.save(child); console.log( `set photoFile for Child:${child.getId()} (${ @@ -59,7 +59,6 @@ export class ChildPhotoUpdateService { return true; } catch (e) { return e.status === 200; - } } } diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index d934d33b22..876c3e032f 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -721,7 +721,7 @@ export const defaultJsonConfig = { [ { "input": "photo", - "id": "specialPhoto", + "id": "photo", "placeholder": "Photo Filename" } ], diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index fcd23f31e2..902e91b188 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -107,11 +107,11 @@ describe("FormComponent", () => { it("sets a new child photo", async () => { const filename = "file/name"; mockChildPhotoService.getImage.and.resolveTo(filename); - testChild.specialPhoto = { + testChild.photo = { path: "", photo: new BehaviorSubject("test"), }; - spyOn(testChild.specialPhoto.photo, "next"); + spyOn(testChild.photo.photo, "next"); await component.uploadChildPhoto({ target: { files: [filename] } }); @@ -119,7 +119,7 @@ describe("FormComponent", () => { filename, testChild.entityId ); - expect(testChild.specialPhoto.photo.next).toHaveBeenCalledWith(filename); + expect(testChild.photo.photo.next).toHaveBeenCalledWith(filename); }); it("reports error when form is invalid", fakeAsync(() => { diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 82206a1281..ff50ee4bef 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -109,7 +109,7 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { ); // Photo does so far only work on the child entity const child: Child = this.entity as Child; - child.specialPhoto.photo.next(await this.childPhotoService.getImage(child)); + child.photo.photo.next(await this.childPhotoService.getImage(child)); } changeFilename(path: string, fromGroupID: string) { From de53618259d6a2551d52a2fb2232d4077e2c16a7 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:52:30 +0200 Subject: [PATCH 035/230] fixed a bug when deleting the filename --- .../entity-components/entity-details/form/form.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 2f4a415adb..55cdb8c9ec 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -47,7 +47,7 @@ /> From 9b2009e323735a2bde87331cc23e7b05f4af626c Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:55:41 +0200 Subject: [PATCH 036/230] undone demo data changes --- .storybook/utils/addDefaultChildPhoto.ts | 5 ++++- .../demo-data-generators/demo-child-generator.service.ts | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.storybook/utils/addDefaultChildPhoto.ts b/.storybook/utils/addDefaultChildPhoto.ts index 970098988a..e60678b18a 100644 --- a/.storybook/utils/addDefaultChildPhoto.ts +++ b/.storybook/utils/addDefaultChildPhoto.ts @@ -3,5 +3,8 @@ import { BehaviorSubject } from "rxjs"; import { SafeUrl } from "@angular/platform-browser"; export function addDefaultChildPhoto(child: Child) { - child.photo.photo = new BehaviorSubject("assets/child.png"); + child.photo = { + path: "", + photo: new BehaviorSubject("assets/child.png"), + }; } diff --git a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts index f3c6c537f1..44e2758f96 100644 --- a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts +++ b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts @@ -7,6 +7,7 @@ import { Injectable } from "@angular/core"; import { DemoDataGenerator } from "../../../core/demo-data/demo-data-generator"; import { faker } from "../../../core/demo-data/faker"; import { centersWithProbability } from "./fixtures/centers"; +import { addDefaultChildPhoto } from "../../../../../.storybook/utils/addDefaultChildPhoto"; export class DemoChildConfig { count: number; @@ -39,16 +40,13 @@ export class DemoChildGenerator extends DemoDataGenerator { child.center = faker.random.arrayElement(centersWithProbability); child.admissionDate = faker.date.past(child.age - 4); - // child.photoFile = "1.jpg"; - - child.photo = { path: "1.jpg", photo: null }; if (faker.datatype.number(100) > 90) { DemoChildGenerator.makeChildDropout(child); } // add default photo for easier use in storybook stories - // addDefaultChildPhoto(child); + addDefaultChildPhoto(child); return child; } From 6b77fb88e852a68e8e17bd0fa763bd5a48e11896 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 08:57:38 +0200 Subject: [PATCH 037/230] changed comment --- .../children/child-photo-service/datatype-photo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index e972510e39..db84ce1f45 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -46,7 +46,7 @@ export class PhotoDatatype implements EntitySchemaDatatype { schemaService: EntitySchemaService, parent: Entity ): Photo { - // Migration of old photoFile values + // Using of old photoFile values if ( parent.hasOwnProperty("photoFile") && parent["photoFile"].trim() !== "" From fee56d17b8446d39323216afba8e3232a113fbde Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 09:37:15 +0200 Subject: [PATCH 038/230] fixed prettier errors --- .../child-photo.service.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index f990cc9818..2f072e7522 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -8,6 +8,17 @@ import { BehaviorSubject } from "rxjs"; providedIn: "root", }) export class ChildPhotoService { + public static getImageFromAssets(photoFile: string): SafeUrl { + if (!photoFile || photoFile.trim() === "") { + return ChildPhotoService.getDefaultImage(); + } + return Child.generatePhotoPath(photoFile); + } + + public static getDefaultImage(): SafeUrl { + return "assets/child.png"; + } + private basePath = "photos/"; constructor(@Optional() private cloudFileService: CloudFileService) {} @@ -45,17 +56,6 @@ export class ChildPhotoService { return image; } - public static getImageFromAssets(photoFile: string): SafeUrl { - if (!photoFile || photoFile.trim() === "") { - return this.getDefaultImage(); - } - return Child.generatePhotoPath(photoFile); - } - - public static getDefaultImage(): SafeUrl { - return "assets/child.png"; - } - /** * Load the image for the given child asynchronously, immediately returning an Observable * that initially emits the static image and later resolves to the image from the cloud service if one exists. From fd851fddca649723b39acb9912ef0836ac0c866e Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 09:39:28 +0200 Subject: [PATCH 039/230] fixed code smells --- .../child-photo-service/children-migration.service.spec.ts | 3 +-- .../children/child-photo-service/datatype-photo.ts | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts index ef2ee38cfb..f6ec043cbc 100644 --- a/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.spec.ts @@ -1,7 +1,6 @@ -import { fakeAsync, TestBed } from "@angular/core/testing"; +import { TestBed } from "@angular/core/testing"; import { ChildrenMigrationService } from "./children-migration.service"; -import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; import { Database } from "../../../core/database/database"; import { PouchDatabase } from "../../../core/database/pouch-database"; import { Child } from "../model/child"; diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index db84ce1f45..ae67ec46c7 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -30,8 +30,6 @@ import { BehaviorSubject } from "rxjs"; export class PhotoDatatype implements EntitySchemaDatatype { public readonly name = "photo"; - constructor() {} - public transformToDatabaseFormat(value: Photo, schema: EntitySchemaField) { if (value.path === schema.defaultValue) { return undefined; From b52dcac767328ea6dd6b04071602effefddf79e0 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 12:52:52 +0200 Subject: [PATCH 040/230] added type info for formControls --- .../edit-age/edit-age.component.ts | 2 +- .../edit-boolean/edit-boolean.component.ts | 2 +- .../form/edit-components/edit-component.ts | 23 +++++++++++++++---- .../edit-configurable-enum.component.ts | 3 ++- .../edit-date/edit-date.component.ts | 2 +- .../edit-long-text.component.ts | 2 +- .../edit-selectable.component.ts | 2 +- .../edit-text/edit-text.component.ts | 2 +- src/app/core/view/dynamic-components-map.ts | 2 ++ 9 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts index efe566c7c9..d0cbc2f43c 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.ts @@ -7,7 +7,7 @@ import { calculateAge } from "../../../../../../utils/utils"; templateUrl: "./edit-age.component.html", styleUrls: ["./edit-age.component.scss"], }) -export class EditAgeComponent extends EditComponent { +export class EditAgeComponent extends EditComponent { getAge(selectedDateOfBirth: string) { return selectedDateOfBirth ? calculateAge(new Date(selectedDateOfBirth)) diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts index ea8f84b8b6..b8e2b47854 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.ts @@ -6,4 +6,4 @@ import { EditComponent } from "../edit-component"; templateUrl: "./edit-boolean.component.html", styleUrls: ["./edit-boolean.component.scss"], }) -export class EditBooleanComponent extends EditComponent {} +export class EditBooleanComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts index dea814e475..71df289d7b 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-component.ts @@ -1,5 +1,5 @@ import { OnInitDynamicComponent } from "../../../../view/dynamic-components/on-init-dynamic-component.interface"; -import { AbstractControl } from "@angular/forms"; +import { AbstractControl, FormControl } from "@angular/forms"; import { FormFieldConfig } from "../FormConfig"; import { EntitySchemaField } from "../../../../entity/schema/entity-schema-field"; @@ -9,16 +9,31 @@ export interface EditComponentConfig { formControl: AbstractControl; } -export abstract class EditComponent implements OnInitDynamicComponent { +export class TypedFormControl extends FormControl { + value: T; + setValue( + value: T, + options?: { + onlySelf?: boolean; + emitEvent?: boolean; + emitModelToViewChange?: boolean; + emitViewToModelChange?: boolean; + } + ) { + super.setValue(value, options); + } +} + +export abstract class EditComponent implements OnInitDynamicComponent { tooltip: string; formControlName: string; placeholder: string; - formControl: AbstractControl; + formControl: TypedFormControl; enumId: string; onInitFromDynamicConfig(config: EditComponentConfig) { this.formControlName = config.formFieldConfig.id; - this.formControl = config.formControl; + this.formControl = config.formControl as TypedFormControl; this.tooltip = config.formFieldConfig.tooltip; this.placeholder = config.formFieldConfig.placeholder || config.propertySchema?.label; diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts index 967af3e7bb..3769825d7e 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,9 +1,10 @@ import { Component } from "@angular/core"; import { EditComponent } from "../edit-component"; +import { ConfigurableEnumValue } from "../../../../../configurable-enum/configurable-enum.interface"; @Component({ selector: "app-edit-configurable-enum", templateUrl: "./edit-configurable-enum.component.html", styleUrls: ["./edit-configurable-enum.component.scss"], }) -export class EditConfigurableEnumComponent extends EditComponent {} +export class EditConfigurableEnumComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts index 976e1748ea..66423a3d7e 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.ts @@ -6,4 +6,4 @@ import { EditComponent } from "../edit-component"; templateUrl: "./edit-date.component.html", styleUrls: ["./edit-date.component.scss"], }) -export class EditDateComponent extends EditComponent {} +export class EditDateComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts index 1834dd967f..28203b4e35 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.ts @@ -6,4 +6,4 @@ import { EditComponent } from "../edit-component"; templateUrl: "./edit-long-text.component.html", styleUrls: ["./edit-long-text.component.scss"], }) -export class EditLongTextComponent extends EditComponent {} +export class EditLongTextComponent extends EditComponent {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts index 74c4e20d22..60b4b46a3c 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.ts @@ -6,7 +6,7 @@ import { EditComponent, EditComponentConfig } from "../edit-component"; templateUrl: "./edit-selectable.component.html", styleUrls: ["./edit-selectable.component.scss"], }) -export class EditSelectableComponent extends EditComponent { +export class EditSelectableComponent extends EditComponent { options: string[]; onInitFromDynamicConfig(config: EditComponentConfig) { super.onInitFromDynamicConfig(config); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts index e92c76e521..49a4e2f61f 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.ts @@ -6,4 +6,4 @@ import { EditComponent } from "../edit-component"; templateUrl: "./edit-text.component.html", styleUrls: ["./edit-text.component.scss"], }) -export class EditTextComponent extends EditComponent {} +export class EditTextComponent extends EditComponent {} diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index feb3113267..0a83eb21d7 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -35,6 +35,7 @@ import { EditSelectableComponent } from "../entity-components/entity-details/for import { EditAgeComponent } from "../entity-components/entity-details/form/edit-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "../entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "../entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component"; +import { EditPhotoComponent } from "../entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -74,4 +75,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditAge", EditAgeComponent], ["EditBoolean", EditBooleanComponent], ["EditLongText", EditLongTextComponent], + ["EditPhoto", EditPhotoComponent], ]); From be9ad6bc744b3872303b956ad7f25dfb8ee6fc74 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 12:56:55 +0200 Subject: [PATCH 041/230] implemented edit photo component --- .../entity-details/entity-details.module.ts | 3 +- .../edit-photo/edit-photo.component.html | 59 +++++++------------ .../edit-photo/edit-photo.component.scss | 19 ++++++ .../edit-photo/edit-photo.component.ts | 13 +++- .../entity-details/form/form.component.scss | 51 ---------------- .../entity-details/form/form.component.ts | 37 +----------- .../entity-details/form/form.stories.ts | 4 +- 7 files changed, 58 insertions(+), 128 deletions(-) diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 8aa348b414..e9ff2abde3 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -28,7 +28,7 @@ import { EditSelectableComponent } from "./form/edit-components/edit-selectable/ import { EditAgeComponent } from "./form/edit-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "./form/edit-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "./form/edit-components/edit-long-text/edit-long-text.component"; -import { EditPhotoComponent } from './form/edit-components/edit-photo/edit-photo.component'; +import { EditPhotoComponent } from "./form/edit-components/edit-photo/edit-photo.component"; @NgModule({ declarations: [ @@ -73,6 +73,7 @@ import { EditPhotoComponent } from './form/edit-components/edit-photo/edit-photo EditAgeComponent, EditBooleanComponent, EditLongTextComponent, + EditPhotoComponent, ], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html index e71d76fddd..5a10dd386f 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.html @@ -1,42 +1,27 @@ -
- child's photo - +child's photo +

No photo set

+ - - - - - - -
+ /> + + diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss index e69de29bb2..e79836ea24 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.scss @@ -0,0 +1,19 @@ +.child-pic-container { + position: relative; + margin-right: 10px; +} + +.child-pic { + width: 150px; + height: 150px; + border-radius: 50%; + object-fit: cover; +} + +.child-pic-photofile { + position: absolute; + left: 1px; + top: 115px; + width: 120px; + background: white; +} diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts index 9521fb3c2d..fcf35ad68a 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.ts @@ -1,9 +1,20 @@ import { Component } from "@angular/core"; import { EditComponent } from "../edit-component"; +import { Photo } from "../../../../../../child-dev-project/children/child-photo-service/photo"; +import { BehaviorSubject } from "rxjs"; +import { ChildPhotoService } from "../../../../../../child-dev-project/children/child-photo-service/child-photo.service"; @Component({ selector: "app-edit-photo", templateUrl: "./edit-photo.component.html", styleUrls: ["./edit-photo.component.scss"], }) -export class EditPhotoComponent extends EditComponent {} +export class EditPhotoComponent extends EditComponent { + changeFilename(path: string) { + const newValue: Photo = { + path: path, + photo: new BehaviorSubject(ChildPhotoService.getImageFromAssets(path)), + }; + this.formControl.setValue(newValue); + } +} diff --git a/src/app/core/entity-components/entity-details/form/form.component.scss b/src/app/core/entity-components/entity-details/form/form.component.scss index e5d7077573..23aed4d2ea 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.scss +++ b/src/app/core/entity-components/entity-details/form/form.component.scss @@ -1,54 +1,3 @@ .edit-button { margin-left: 10px; } - -.mat-form-field { - margin-right: 10px; -} - -.child-pic-container { - position: relative; - margin-right: 10px; -} - -.child-pic { - width: 150px; - height: 150px; - border-radius: 50%; - object-fit: cover; -} - -.child-pic-upload { - position: absolute; - left: 0; - width: 120px; - height: 150px; - - border: none; - background: none; - cursor: pointer; -} - -.upload-icon { - font-size: 2em; -} - -.child-pic-photofile { - position: absolute; - left: 1px; - top: 115px; - width: 120px; - background: white; -} - -.locked-icon { - line-height: 20px; - padding-left: 10px; - color: black; -} - -.mat-icon{ - font-size: 1.25em; - color: grey; - vertical-align: bottom; -} diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 1b30d4adee..1d5a5f9b77 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -6,15 +6,11 @@ import { PanelConfig } from "../EntityDetailsConfig"; import { Entity } from "../../../entity/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { SessionService } from "../../../session/session-service/session.service"; -import { ChildPhotoService } from "../../../../child-dev-project/children/child-photo-service/child-photo.service"; import { AlertService } from "../../../alerts/alert.service"; import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; -import { calculateAge, getParentUrl } from "../../../../utils/utils"; -import { Child } from "../../../../child-dev-project/children/model/child"; +import { getParentUrl } from "../../../../utils/utils"; import { OperationType } from "../../../permissions/entity-permissions.service"; import { EntitySchemaService } from "../../../entity/schema/entity-schema.service"; -import { Photo } from "../../../../child-dev-project/children/child-photo-service/photo"; -import { BehaviorSubject } from "rxjs"; /** * This component creates a form based on the passed config. @@ -32,7 +28,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { creatingNew = false; isAdminUser: boolean; - enablePhotoUpload = false; editing: boolean = false; config: FormConfig; @@ -45,7 +40,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { private fb: FormBuilder, private entityMapperService: EntityMapperService, private alertService: AlertService, - private childPhotoService: ChildPhotoService, private router: Router, private sessionService: SessionService, private entitySchemaService: EntitySchemaService @@ -70,13 +64,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { switchEdit() { this.editing = !this.editing; this.initForm(); - this.enablePhotoUpload = this.childPhotoService.canSetImage(); - } - - calculateAge(selectedDateOfBirth: string) { - return selectedDateOfBirth - ? calculateAge(new Date(selectedDateOfBirth)) - : ""; } async save(): Promise { @@ -102,28 +89,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { } } - /** - * hands over the selected file to the cloudFileService together with the childId - * @param event The event of the file upload dialog - */ - async uploadChildPhoto(event) { - await this.childPhotoService.setImage( - event.target.files[0], - this.entity.entityId - ); - // Photo does so far only work on the child entity - const child: Child = this.entity as Child; - child.photo.photo.next(await this.childPhotoService.getImage(child)); - } - - changeFilename(path: string, fromGroupID: string) { - const newValue: Photo = { - path: path, - photo: new BehaviorSubject(ChildPhotoService.getImageFromAssets(path)), - }; - this.form.get(fromGroupID).setValue(newValue); - } - private initForm(): void { this.columns = this.config.cols.map((column) => column.map((row) => { diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index fb7a589584..d10a8edab7 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -43,8 +43,8 @@ const testConfig = { cols: [ [ { - input: "photo", - id: "photoFile", + input: "EditPhoto", + id: "photo", placeholder: "Photo Filename", }, ], From f5a1d741238a5f0d3d1e4320588b664bd2f8c1ba Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 14:28:44 +0200 Subject: [PATCH 042/230] fix config to use new form syntax --- .../child-photo.service.ts | 6 +- .../child-photo-service/datatype-photo.ts | 1 + .../child-dev-project/children/model/child.ts | 19 +- src/app/core/config/config-fix.ts | 237 +++--------------- .../configurable-enum-datatype.ts | 1 + .../entity-details/form/form.stories.ts | 9 +- .../schema-datatypes/datatype-date-only.ts | 1 + .../entity/schema-datatypes/datatype-date.ts | 1 + .../schema-datatypes/datatype-default.ts | 1 + .../schema-datatypes/datatype-number.ts | 2 + .../schema-datatypes/datatype-string.ts | 1 + 11 files changed, 59 insertions(+), 220 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index 2f072e7522..cb9c1c9229 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -10,15 +10,11 @@ import { BehaviorSubject } from "rxjs"; export class ChildPhotoService { public static getImageFromAssets(photoFile: string): SafeUrl { if (!photoFile || photoFile.trim() === "") { - return ChildPhotoService.getDefaultImage(); + return Child.getDefaultImage(); } return Child.generatePhotoPath(photoFile); } - public static getDefaultImage(): SafeUrl { - return "assets/child.png"; - } - private basePath = "photos/"; constructor(@Optional() private cloudFileService: CloudFileService) {} diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index ae67ec46c7..946471ad13 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -29,6 +29,7 @@ import { BehaviorSubject } from "rxjs"; */ export class PhotoDatatype implements EntitySchemaDatatype { public readonly name = "photo"; + public readonly editComponent = "EditPhoto"; public transformToDatabaseFormat(value: Photo, schema: EntitySchemaField) { if (value.path === schema.defaultValue) { diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index ca8116c983..a4ccc9ef26 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -22,7 +22,7 @@ import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; import { calculateAge } from "../../../utils/utils"; import { Photo } from "../child-photo-service/photo"; -import { ChildPhotoService } from "../child-photo-service/child-photo.service"; +import { SafeUrl } from "@angular/platform-browser"; export type Center = ConfigurableEnumValue; @DatabaseEntity("Child") @@ -33,6 +33,10 @@ export class Child extends Entity { return instance; } + public static getDefaultImage(): SafeUrl { + return "assets/child.png"; + } + /** * Returns the full relative filePath to a child photo given a filename, adding the relevant folders to it. * @param filename The given filename with file extension. @@ -41,7 +45,7 @@ export class Child extends Entity { return "assets/child-photos/" + filename; } - @DatabaseField() name: string; + @DatabaseField({ label: "Name" }) name: string; @DatabaseField({ label: "PN" }) projectNumber: string; // project number @DatabaseField({ dataType: "date-only", @@ -57,7 +61,7 @@ export class Child extends Entity { editComponent: "EditSelectable", }) gender: Gender; // M or F - @DatabaseField() religion: string = ""; + @DatabaseField({ label: "Religion" }) religion: string = ""; @DatabaseField({ dataType: "configurable-enum", @@ -68,9 +72,9 @@ export class Child extends Entity { @DatabaseField({ label: "Admission" }) admissionDate: Date; @DatabaseField({ label: "Status" }) status: string = ""; - @DatabaseField() dropoutDate: Date; - @DatabaseField() dropoutType: string; - @DatabaseField() dropoutRemarks: string; + @DatabaseField({ label: "Dropout Date" }) dropoutDate: Date; + @DatabaseField({ label: "Dropout Type" }) dropoutType: string; + @DatabaseField({ label: "Dropout remarks" }) dropoutRemarks: string; /** current school (as determined through the ChildSchoolRelation docs) set during loading through ChildrenService */ schoolId: string = ""; @@ -79,7 +83,8 @@ export class Child extends Entity { @DatabaseField({ dataType: "photo", - defaultValue: ChildPhotoService.getDefaultImage(), + defaultValue: Child.getDefaultImage(), + label: "Photo Filename", }) photo: Photo; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index e6dd6ad06c..bdd363252b 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -619,122 +619,35 @@ export const defaultJsonConfig = { "component": "Form", "config": { "cols": [ + [{ "id": "photo" }], [ - { - "input": "photo", - "id": "photo", - "placeholder": "Photo Filename" - } - ], - [ - { - "input": "text", - "id": "name", - "placeholder": "Name", - "required": true - }, - { - "input": "text", - "id": "projectNumber", - "placeholder": "Project Number" - }, - { - "input": "configurable-enum-select", - "id": "center", - "placeholder": "Center", - "enumId": "center" - }, - { - "input": "text", - "id": "status", - "placeholder": "Project Status" - } + { "id": "name", "required": true }, + { "id": "projectNumber" }, + { "id": "center" }, + { "id": "status" } ], [ { - "input": "age", "tooltip": "This field is read-only. Edit Date of Birth to change age. Select Jan 1st if you only know the year of birth.", - "id": "dateOfBirth", - "placeholder": "Date of Birth" + "id": "dateOfBirth" }, - { - "input": "select", - "id": "gender", - "placeholder": "Gender", - "options": [ - "M", - "F" - ] - }, - { - "input": "text", - "id": "motherTongue", - "placeholder": "Mother Tongue" - }, - { - "input": "text", - "id": "religion", - "placeholder": "Religion" - } + { "id": "gender" }, + { "id": "motherTongue" }, + { "id": "religion" } ], [ - { - "input": "datepicker", - "id": "admissionDate", - "placeholder": "Admission Date" - }, - { - "input": "configurable-enum-select", - "id": "has_aadhar", - "placeholder": "Aadhar Status", - "enumId": "document-status" - }, - { - "input": "configurable-enum-select", - "id": "has_kanyashree", - "placeholder": "Kanyashree Status", - "enumId": "document-status" - }, - { - "input": "configurable-enum-select", - "id": "has_bankAccount", - "placeholder": "Bank Account Status", - "enumId": "document-status" - }, - { - "input": "configurable-enum-select", - "id": "has_rationCard", - "placeholder": "Ration Card Status", - "enumId": "document-status" - }, - { - "input": "configurable-enum-select", - "id": "has_BplCard", - "placeholder": "BPL Card Status", - "enumId": "document-status" - } + { "id": "admissionDate" }, + { "id": "has_aadhar" }, + { "id": "has_kanyashree" }, + { "id": "has_bankAccount" }, + { "id": "has_rationCard" }, + { "id": "has_BplCard" } ], [ - { - "input": "text", - "id": "address", - "placeholder": "Address" - }, - { - "input": "text", - "id": "phone", - "placeholder": "Phone No." - }, - { - "input": "text", - "id": "guardianName", - "placeholder": "Guardians" - }, - { - "input": "text", - "id": "preferredTimeForGuardianMeeting", - "placeholder": "Preferred time for guardians meeting" - } + { "id": "address" }, + { "id": "phone" }, + { "id": "guardianName" }, + { "id": "preferredTimeForGuardianMeeting" } ] ] } @@ -790,74 +703,14 @@ export const defaultJsonConfig = { "component": "Form", "config": { "cols": [ - [ - { - "input": "select", - "id": "health_vaccinationStatus", - "placeholder": "Vaccination Status", - "options": [ - "Good", - "Vaccination Due", - "Needs Checking", - "No Card/Information" - ] - } - ], - [ - { - "input": "select", - "id": "health_eyeHealthStatus", - "placeholder": "Eye Status", - "options": [ - "Good", - "Has Glasses", - "Needs Glasses", - "Needs Checkup" - ] - } - ], - [ - { - "input": "text", - "id": "health_bloodGroup", - "placeholder": "Blood Group" - } - ], - [ - { - "input": "datepicker", - "id": "health_lastDentalCheckup", - "placeholder": "Last Dental Check-Up" - } - ], - [ - { - "input": "datepicker", - "id": "health_lastEyeCheckup", - "placeholder": "Last Eye Check-Up" - } - ], - [ - { - "input": "datepicker", - "id": "health_lastENTCheckup", - "placeholder": "Last ENT Check-Up" - } - ], - [ - { - "input": "datepicker", - "id": "health_lastVitaminD", - "placeholder": "Last Vitamin D" - } - ], - [ - { - "input": "datepicker", - "id": "health_lastDeworming", - "placeholder": "Last De-Worming" - } - ] + [{ "id": "health_vaccinationStatus" }], + [{ "id": "health_eyeHealthStatus" }], + [{ "id": "health_bloodGroup" }], + [{ "id": "health_lastDentalCheckup" }], + [{ "id": "health_lastEyeCheckup" }], + [{ "id": "health_lastENTCheckup" }], + [{ "id": "health_lastVitaminD" }], + [{ "id": "health_lastDeworming" }] ] } }, @@ -970,27 +823,9 @@ export const defaultJsonConfig = { "component": "Form", "config": { "cols": [ - [ - { - "input": "datepicker", - "id": "dropoutDate", - "placeholder": "Dropout Date" - } - ], - [ - { - "input": "text", - "id": "dropoutType", - "placeholder": "Dropout Type" - } - ], - [ - { - "input": "text", - "id": "dropoutRemarks", - "placeholder": "Dropout Remarks" - } - ] + [{ "id": "dropoutDate" }], + [{ "id": "dropoutType" }], + [{ "id": "dropoutRemarks" }] ] } } @@ -1167,19 +1002,19 @@ export const defaultJsonConfig = { "permissions": { }, "attributes": [ - {"name": "address", "schema": { "dataType": "string" } }, - {"name": "phone", "schema": { "dataType": "string" } }, - {"name": "guardianName", "schema": { "dataType": "string" } }, - {"name": "preferredTimeForGuardianMeeting", "schema": { "dataType": "string" } }, + {"name": "address", "schema": { "dataType": "string", label: "Address" } }, + {"name": "phone", "schema": { "dataType": "string", label: "Phone No." } }, + {"name": "guardianName", "schema": { "dataType": "string", label: "Guardians" } }, + {"name": "preferredTimeForGuardianMeeting", "schema": { "dataType": "string", label: "Preferred time for guardians meeting" } }, {"name": "has_aadhar", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Aadhar" } }, {"name": "has_bankAccount", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Bank Account" } }, {"name": "has_kanyashree", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Kanyashree" } }, {"name": "has_rationCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "Ration Card" } }, {"name": "has_BplCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "BPL Card" } }, - {"name": "health_vaccinationStatus", "schema": { "dataType": "string", label: "Vaccination Status" } }, + {"name": "health_vaccinationStatus", "schema": { "dataType": "string", label: "Vaccination Status", ext: ["", "Good", "Vaccination Due", "Needs Checking", "No Card/Information"] } }, {"name": "health_bloodGroup", "schema": { "dataType": "string", label: "Blood Group" } }, {"name": "health_lastDentalCheckup", "schema": { "dataType": "Date", label: "Last Dental Check-Up" } }, - {"name": "health_lastEyeCheckup", "schema": { "dataType": "Date", label: "Last Eye Check-Up" } }, + {"name": "health_lastEyeCheckup", "schema": { "dataType": "Date", label: "Last Eye Check-Up", ext: ["", "Good", "Has Glasses", "Needs Glasses", "Needs Checkup"] } }, {"name": "health_lastENTCheckup", "schema": { "dataType": "Date", label: "Last ENT Check-Up" } }, {"name": "health_eyeHealthStatus", "schema": { "dataType": "string", label: "Eye Status" } }, {"name": "health_lastVitaminD", "schema": { "dataType": "Date", label: "Last Vitamin D" } }, diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index d5192bad4b..c7ba454eff 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -11,6 +11,7 @@ export class ConfigurableEnumDatatype implements EntitySchemaDatatype { public readonly name = "configurable-enum"; public readonly viewComponent = "DisplayConfigurableEnum"; + public readonly editComponent = "EditConfigurableEnum"; constructor(private configService: ConfigService) {} diff --git a/src/app/core/entity-components/entity-details/form/form.stories.ts b/src/app/core/entity-components/entity-details/form/form.stories.ts index d10a8edab7..77cc89e026 100644 --- a/src/app/core/entity-components/entity-details/form/form.stories.ts +++ b/src/app/core/entity-components/entity-details/form/form.stories.ts @@ -43,16 +43,12 @@ const testConfig = { cols: [ [ { - input: "EditPhoto", id: "photo", - placeholder: "Photo Filename", }, ], [ { - input: "EditText", id: "name", - placeholder: "Name", required: true, }, { @@ -77,8 +73,8 @@ const testConfig = { "No Card/Information", ], }, - // ], - // [ + ], + [ { input: "EditConfigurableEnum", id: "has_rationCard", @@ -86,7 +82,6 @@ const testConfig = { enumId: "document-status", }, { - input: "EditDate", id: "admissionDate", }, { diff --git a/src/app/core/entity/schema-datatypes/datatype-date-only.ts b/src/app/core/entity/schema-datatypes/datatype-date-only.ts index 7d5488814d..1288e49617 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date-only.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date-only.ts @@ -29,6 +29,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const dateOnlyEntitySchemaDatatype: EntitySchemaDatatype = { name: "date-only", viewComponent: "DisplayDate", + editComponent: "EditDate", transformToDatabaseFormat: (value: Date) => { if (!(value instanceof Date)) { diff --git a/src/app/core/entity/schema-datatypes/datatype-date.ts b/src/app/core/entity/schema-datatypes/datatype-date.ts index 3790014757..82c5c10f7d 100644 --- a/src/app/core/entity/schema-datatypes/datatype-date.ts +++ b/src/app/core/entity/schema-datatypes/datatype-date.ts @@ -30,6 +30,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const dateEntitySchemaDatatype: EntitySchemaDatatype = { name: "date", viewComponent: "DisplayDate", + editComponent: "EditDate", transformToDatabaseFormat: (value: Date) => { // TODO: should date format be saved as date object or as string "YYYY-mm-dd"? diff --git a/src/app/core/entity/schema-datatypes/datatype-default.ts b/src/app/core/entity/schema-datatypes/datatype-default.ts index f0b41a63c7..7ed7bf76b9 100644 --- a/src/app/core/entity/schema-datatypes/datatype-default.ts +++ b/src/app/core/entity/schema-datatypes/datatype-default.ts @@ -25,6 +25,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const defaultEntitySchemaDatatype: EntitySchemaDatatype = { name: "any", viewComponent: "DisplayText", + editComponent: "EditText", transformToDatabaseFormat: (value) => { return value; diff --git a/src/app/core/entity/schema-datatypes/datatype-number.ts b/src/app/core/entity/schema-datatypes/datatype-number.ts index f6a9061069..5fe9746861 100644 --- a/src/app/core/entity/schema-datatypes/datatype-number.ts +++ b/src/app/core/entity/schema-datatypes/datatype-number.ts @@ -31,6 +31,8 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; */ export const numberEntitySchemaDatatype: EntitySchemaDatatype = { name: "number", + viewComponent: "DisplayText", + editComponent: "EditText", transformToDatabaseFormat: (value) => { return Number(value); diff --git a/src/app/core/entity/schema-datatypes/datatype-string.ts b/src/app/core/entity/schema-datatypes/datatype-string.ts index b2b9e4f524..3e2ae22007 100644 --- a/src/app/core/entity/schema-datatypes/datatype-string.ts +++ b/src/app/core/entity/schema-datatypes/datatype-string.ts @@ -32,6 +32,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const stringEntitySchemaDatatype: EntitySchemaDatatype = { name: "string", viewComponent: "DisplayText", + editComponent: "EditText", transformToDatabaseFormat: (value) => { return String(value); From c162766690897debfea824d397b904724dd0c339 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 14:38:49 +0200 Subject: [PATCH 043/230] fix config for school to use new syntax --- .../child-dev-project/schools/model/school.ts | 28 +++--- src/app/core/config/config-fix.ts | 88 +++---------------- 2 files changed, 28 insertions(+), 88 deletions(-) diff --git a/src/app/child-dev-project/schools/model/school.ts b/src/app/child-dev-project/schools/model/school.ts index ab5d81e123..3f4821ccc9 100644 --- a/src/app/child-dev-project/schools/model/school.ts +++ b/src/app/child-dev-project/schools/model/school.ts @@ -4,17 +4,23 @@ import { DatabaseField } from "../../../core/entity/database-field.decorator"; @DatabaseEntity("School") export class School extends Entity { - @DatabaseField() name: string = ""; - @DatabaseField() address: string = ""; - @DatabaseField() medium: string = ""; - @DatabaseField() remarks: string = ""; - @DatabaseField() website: string = ""; - @DatabaseField() privateSchool: boolean; - @DatabaseField() phone: string = ""; - @DatabaseField() upToClass: number; - @DatabaseField() academicBoard: string = ""; - @DatabaseField() timing: string = ""; - @DatabaseField() workingDays: string = ""; + @DatabaseField({ label: "Name" }) name: string = ""; + @DatabaseField({ label: "Address" }) address: string = ""; + @DatabaseField({ label: "Medium" }) medium: string = ""; + @DatabaseField({ label: "Remarks" }) remarks: string = ""; + @DatabaseField({ label: "Website" }) website: string = ""; + @DatabaseField({ + label: "Private School", + editComponent: "EditBoolean", + viewComponent: "DisplayCheckmark", + }) + privateSchool: boolean; + @DatabaseField({ label: "Contact Number" }) phone: string = ""; + @DatabaseField({ label: "Teaching up to class" }) upToClass: number; + @DatabaseField({ label: "Board" }) academicBoard: string = ""; + @DatabaseField({ label: "School Timing" }) timing: string = ""; + @DatabaseField({ label: "Working Days", editComponent: "EditLongText" }) + workingDays: string = ""; public toString() { return this.name; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index bdd363252b..d648ddbf0b 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -359,83 +359,17 @@ export const defaultJsonConfig = { "component": "Form", "config": { "cols": [ - [ - { - "input": "text", - "id": "name", - "placeholder": "Name" - } - ], - [ - { - "input": "text", - "id": "medium", - "placeholder": "Medium" - } - ], - [ - { - "input": "checkbox", - "id": "privateSchool", - "placeholder": "Private School" - } - ], - [ - { - "input": "text", - "id": "academicBoard", - "placeholder": "Board" - } - ], - [ - { - "input": "text", - "id": "phone", - "placeholder": "Contact Number" - } - ], - [ - { - "input": "text", - "id": "address", - "placeholder": "Address" - } - ], - [ - { - "input": "text", - "id": "website", - "placeholder": "Website" - } - ], - [ - { - "input": "text", - "id": "timing", - "placeholder": "School Timing" - } - ], - [ - { - "input": "text", - "id": "workingDays", - "placeholder": "Working Days" - } - ], - [ - { - "input": "text", - "id": "upToClass", - "placeholder": "Teaching up to class" - } - ], - [ - { - "input": "textarea", - "id": "remarks", - "placeholder": "Remarks" - } - ] + [{ "id": "name" }], + [{ "id": "medium" }], + [{ "id": "privateSchool" }], + [{ "id": "academicBoard" }], + [{ "id": "phone" }], + [{ "id": "address" }], + [{ "id": "website" }], + [{ "id": "timing" }], + [{ "id": "workingDays" }], + [{ "id": "upToClass" }], + [{ "id": "remarks" }] ] } } From 500f44c622a4f994193e07ba072714206ff8457b Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 17 May 2021 15:24:06 +0200 Subject: [PATCH 044/230] fixed tests --- .../entity-details/entity-details.module.ts | 2 -- .../edit-age/edit-age.component.spec.ts | 22 +++++++++----- .../edit-boolean.component.spec.ts | 22 +++++++++----- .../edit-configurable-enum.component.spec.ts | 29 +++++++++++++----- .../edit-date/edit-date.component.spec.ts | 22 +++++++++----- .../edit-long-text.component.spec.ts | 22 +++++++++----- .../edit-photo/edit-photo.component.spec.ts | 22 +++++++++----- .../edit-selectable.component.spec.ts | 22 +++++++++----- .../edit-text/edit-text.component.spec.ts | 22 +++++++++----- .../photo/photo.component.html | 1 - .../photo/photo.component.scss | 0 .../photo/photo.component.spec.ts | 25 ---------------- .../edit-components/photo/photo.component.ts | 15 ---------- .../form/form.component.spec.ts | 30 +------------------ 14 files changed, 128 insertions(+), 128 deletions(-) delete mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html delete mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss delete mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts delete mode 100644 src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index e9ff2abde3..3caf4e7c7a 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -20,7 +20,6 @@ import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { PermissionsModule } from "../../permissions/permissions.module"; -import { PhotoComponent } from "./form/edit-components/photo/photo.component"; import { EditConfigurableEnumComponent } from "./form/edit-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./form/edit-components/edit-text/edit-text.component"; import { EditDateComponent } from "./form/edit-components/edit-date/edit-date.component"; @@ -34,7 +33,6 @@ import { EditPhotoComponent } from "./form/edit-components/edit-photo/edit-photo declarations: [ EntityDetailsComponent, FormComponent, - PhotoComponent, EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts index 3dfbde08b6..882dc5eb27 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-age/edit-age.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditAgeComponent } from './edit-age.component'; +import { EditAgeComponent } from "./edit-age.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { FormControl, FormGroup } from "@angular/forms"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -describe('EditAgeComponent', () => { +describe("EditAgeComponent", () => { let component: EditAgeComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditAgeComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditAgeComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditAgeComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts index a3bb963dc0..054599d353 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-boolean/edit-boolean.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditBooleanComponent } from './edit-boolean.component'; +import { EditBooleanComponent } from "./edit-boolean.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { FormControl, FormGroup } from "@angular/forms"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -describe('EditBooleanComponent', () => { +describe("EditBooleanComponent", () => { let component: EditBooleanComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditBooleanComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditBooleanComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditBooleanComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts index 750e29e2cc..40725919f7 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts @@ -1,25 +1,40 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditConfigurableEnumComponent } from './edit-configurable-enum.component'; +import { EditConfigurableEnumComponent } from "./edit-configurable-enum.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { FormControl, FormGroup } from "@angular/forms"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { ConfigService } from "../../../../../config/config.service"; -describe('EditConfigurableEnumComponent', () => { +describe("EditConfigurableEnumComponent", () => { let component: EditConfigurableEnumComponent; let fixture: ComponentFixture; + let mockConfigService: jasmine.SpyObj; + beforeEach(async () => { + mockConfigService = jasmine.createSpyObj(["getConfig"]); + mockConfigService.getConfig.and.returnValue([]); await TestBed.configureTestingModule({ - declarations: [ EditConfigurableEnumComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditConfigurableEnumComponent], + providers: [{ provide: ConfigService, useValue: mockConfigService }], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditConfigurableEnumComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); + component.enumId = ""; fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts index b4fbc9953c..d06c51bb1c 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-date/edit-date.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditDateComponent } from './edit-date.component'; +import { EditDateComponent } from "./edit-date.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { FormControl, FormGroup } from "@angular/forms"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -describe('EditDateComponent', () => { +describe("EditDateComponent", () => { let component: EditDateComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditDateComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditDateComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditDateComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts index d55d04d68f..e9aaa46860 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-long-text/edit-long-text.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditLongTextComponent } from './edit-long-text.component'; +import { EditLongTextComponent } from "./edit-long-text.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { FormControl, FormGroup } from "@angular/forms"; -describe('EditLongTextComponent', () => { +describe("EditLongTextComponent", () => { let component: EditLongTextComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditLongTextComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditLongTextComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditLongTextComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts index ee833438b7..060e33270c 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-photo/edit-photo.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditPhotoComponent } from './edit-photo.component'; +import { EditPhotoComponent } from "./edit-photo.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { FormControl, FormGroup } from "@angular/forms"; -describe('EditPhotoComponent', () => { +describe("EditPhotoComponent", () => { let component: EditPhotoComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditPhotoComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditPhotoComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditPhotoComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts index bca0cfb2ce..34348c518a 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-selectable/edit-selectable.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditSelectableComponent } from './edit-selectable.component'; +import { EditSelectableComponent } from "./edit-selectable.component"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { FormControl, FormGroup } from "@angular/forms"; -describe('EditSelectableComponent', () => { +describe("EditSelectableComponent", () => { let component: EditSelectableComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditSelectableComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditSelectableComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditSelectableComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts index f5d2bbe924..2d00c91327 100644 --- a/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/edit-components/edit-text/edit-text.component.spec.ts @@ -1,25 +1,33 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditTextComponent } from './edit-text.component'; +import { EditTextComponent } from "./edit-text.component"; +import { FormControl, FormGroup } from "@angular/forms"; +import { EntityDetailsModule } from "../../../entity-details.module"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -describe('EditTextComponent', () => { +describe("EditTextComponent", () => { let component: EditTextComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditTextComponent ] - }) - .compileComponents(); + imports: [EntityDetailsModule, NoopAnimationsModule], + declarations: [EditTextComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditTextComponent); component = fixture.componentInstance; + const formControl = new FormControl(); + const formGroup = new FormGroup({}); + component.formControlName = "testControl"; + component.formControl = formControl; + formGroup.registerControl(component.formControlName, formControl); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html deleted file mode 100644 index 4a5f565c4c..0000000000 --- a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.html +++ /dev/null @@ -1 +0,0 @@ -

photo works!

diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts deleted file mode 100644 index 57e25c8412..0000000000 --- a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PhotoComponent } from './photo.component'; - -describe('PhotoComponent', () => { - let component: PhotoComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ PhotoComponent ] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(PhotoComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts b/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts deleted file mode 100644 index cbb536eeb6..0000000000 --- a/src/app/core/entity-components/entity-details/form/edit-components/photo/photo.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-photo', - templateUrl: './photo.component.html', - styleUrls: ['./photo.component.scss'] -}) -export class PhotoComponent implements OnInit { - - constructor() { } - - ngOnInit(): void { - } - -} diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index 9bdcdffc49..5e3c35e4af 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -7,8 +7,6 @@ import { } from "@angular/core/testing"; import { FormComponent } from "./form.component"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { BehaviorSubject } from "rxjs"; -import { SafeUrl } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; import { Router } from "@angular/router"; import { EntityDetailsModule } from "../entity-details.module"; @@ -96,13 +94,6 @@ describe("FormComponent", () => { expect(component.creatingNew).toBe(true); }); - it("changes enablePhotoUpload state", () => { - expect(component.enablePhotoUpload).toBe(false); - mockChildPhotoService.canSetImage.and.returnValues(true); - component.switchEdit(); - expect(component.enablePhotoUpload).toBe(true); - }); - it("calls router once a new child is saved", async () => { spyOnProperty(component.form, "valid").and.returnValue(true); const router = fixture.debugElement.injector.get(Router); @@ -112,24 +103,6 @@ describe("FormComponent", () => { expect(router.navigate).toHaveBeenCalledWith(["", testChild.getId()]); }); - it("sets a new child photo", async () => { - const filename = "file/name"; - mockChildPhotoService.getImage.and.resolveTo(filename); - testChild.photo = { - path: "", - photo: new BehaviorSubject("test"), - }; - spyOn(testChild.photo.photo, "next"); - - await component.uploadChildPhoto({ target: { files: [filename] } }); - - expect(mockChildPhotoService.setImage).toHaveBeenCalledWith( - filename, - testChild.entityId - ); - expect(testChild.photo.photo.next).toHaveBeenCalledWith(filename); - }); - it("reports error when form is invalid", fakeAsync(() => { const alertService = fixture.debugElement.injector.get(AlertService); spyOn(alertService, "addDanger"); @@ -161,7 +134,7 @@ describe("FormComponent", () => { it("should add column definitions from property schema", () => { class Test extends Entity { - @DatabaseField({ label: "Predefined label" }) propertyField: string; + @DatabaseField() propertyField: string; } mockEntitySchemaService.getComponent.and.returnValue("PredefinedComponent"); @@ -191,7 +164,6 @@ describe("FormComponent", () => { { id: "propertyField", input: "PredefinedComponent", - placeholder: "Predefined label", }, ], ]); From 46b91ac6ac07526d1a60f7f5e284f3e27413d6d7 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 18 May 2021 07:23:12 +0200 Subject: [PATCH 045/230] added story for entity subrecord --- src/app/core/config/config.service.ts | 2 +- .../entity-subrecord.stories.ts | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts diff --git a/src/app/core/config/config.service.ts b/src/app/core/config/config.service.ts index cf636a2b62..903c369a3d 100644 --- a/src/app/core/config/config.service.ts +++ b/src/app/core/config/config.service.ts @@ -17,7 +17,7 @@ export class ConfigService { */ public configUpdated: BehaviorSubject; - constructor(@Optional() private loggingService: LoggingService) { + constructor(@Optional() private loggingService?: LoggingService) { this.config.data = defaultJsonConfig; this.configUpdated = new BehaviorSubject(this.config); } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts new file mode 100644 index 0000000000..e1feae85ec --- /dev/null +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts @@ -0,0 +1,87 @@ +import { moduleMetadata } from "@storybook/angular"; +import { RouterTestingModule } from "@angular/router/testing"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { Meta, Story } from "@storybook/angular/types-6-0"; +import { EntitySubrecordComponent } from "./entity-subrecord.component"; +import { EntitySubrecordModule } from "../entity-subrecord.module"; +import { Note } from "../../../../child-dev-project/notes/model/note"; +import { EntityMapperService } from "../../../entity/entity-mapper.service"; +import { DatePipe } from "@angular/common"; +import { DemoNoteGeneratorService } from "../../../../child-dev-project/notes/demo-data/demo-note-generator.service"; +import { ConfigService } from "../../../config/config.service"; +import { EntitySchemaService } from "../../../entity/schema/entity-schema.service"; +import { DemoChildGenerator } from "../../../../child-dev-project/children/demo-data-generators/demo-child-generator.service"; +import { DemoUserGeneratorService } from "../../../user/demo-user-generator.service"; +import { ColumnDescriptionInputType } from "../column-description-input-type.enum"; +import { ConfigurableEnumDatatype } from "../../../configurable-enum/configurable-enum-datatype/configurable-enum-datatype"; +import { MatNativeDateModule } from "@angular/material/core"; +import { INTERACTION_TYPE_CONFIG_ID } from "../../../../child-dev-project/notes/model/interaction-type.interface"; + +const configService = new ConfigService(); +const schemaService = new EntitySchemaService(); +export default { + title: "Core/EntitySubrecord", + component: EntitySubrecordComponent, + decorators: [ + moduleMetadata({ + imports: [ + EntitySubrecordModule, + RouterTestingModule, + BrowserAnimationsModule, + MatNativeDateModule, + ], + providers: [ + { + provide: EntityMapperService, + useValue: { save: () => null, remove: () => null }, + }, + { provide: EntitySchemaService, useValue: schemaService }, + { provide: ConfigService, useValue: configService }, + DatePipe, + ], + }), + ], +} as Meta; + +const Template: Story> = ( + args: EntitySubrecordComponent +) => ({ + component: EntitySubrecordComponent, + props: args, +}); + +schemaService.registerSchemaDatatype( + new ConfigurableEnumDatatype(configService) +); +const childGenerator = new DemoChildGenerator({ count: 10 }); +const userGenerator = new DemoUserGeneratorService(); +const data = new DemoNoteGeneratorService( + { minNotesPerChild: 5, maxNotesPerChild: 10, groupNotes: 2 }, + childGenerator, + userGenerator, + schemaService, + configService +).generateEntities(); + +export const Primary = Template.bind({}); +Primary.args = { + columns: [ + { + name: "date", + label: "Date", + inputType: ColumnDescriptionInputType.DATE, + }, + { + name: "subject", + label: "Subject", + inputType: ColumnDescriptionInputType.TEXT, + }, + { + name: "category", + label: "Category", + inputType: ColumnDescriptionInputType.CONFIGURABLE_ENUM, + enumId: INTERACTION_TYPE_CONFIG_ID, + }, + ], + records: data, +}; From 80c267016711d2e41bca4dd621830506cc84d638 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 18 May 2021 09:04:19 +0200 Subject: [PATCH 046/230] using form components in entity subrecord --- .../entity-subrecord/column-description.ts | 2 + .../entity-subrecord.module.ts | 6 + .../entity-subrecord.component.html | 146 +++--------------- .../entity-subrecord.component.ts | 86 ++++++----- .../entity-subrecord.stories.ts | 3 + 5 files changed, 82 insertions(+), 161 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/column-description.ts b/src/app/core/entity-components/entity-subrecord/column-description.ts index de43cf5511..eda7e21748 100644 --- a/src/app/core/entity-components/entity-subrecord/column-description.ts +++ b/src/app/core/entity-components/entity-subrecord/column-description.ts @@ -34,6 +34,8 @@ export interface ColumnDescription { /** How the value of this column is displayed and what kind of form field is provided to edit it */ inputType: ColumnDescriptionInputType; + component?: string; + /** Array of possible values for editing this column; required for inputTypes select and autocomplete */ selectValues?: Array<{ value: any; label: string }>; diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 60b6396ec7..25fa411b21 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -17,6 +17,9 @@ import { MatSnackBarModule } from "@angular/material/snack-bar"; import { MatButtonModule } from "@angular/material/button"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { MatTooltipModule } from "@angular/material/tooltip"; +import { ViewModule } from "../../view/view.module"; +import { ReactiveFormsModule } from "@angular/forms"; +import { EntityDetailsModule } from "../entity-details/entity-details.module"; @NgModule({ declarations: [EntitySubrecordComponent, KeysPipe], @@ -37,6 +40,9 @@ import { MatTooltipModule } from "@angular/material/tooltip"; MatButtonModule, ConfigurableEnumModule, MatTooltipModule, + ViewModule, + ReactiveFormsModule, + EntityDetailsModule, ], exports: [EntitySubrecordComponent, KeysPipe], }) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index 0ac99ca69a..92ecd1b3e7 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -17,127 +17,24 @@ -
+ - {{ col.valueFunction(rec) }} -
- -
- - - - - - - - - - - - - - - {{ option.label }} - - - - - - {{ option.label }} - - - - - {{ o.label }} - - - -
+ @@ -162,8 +59,8 @@
- +
diff --git a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts index d9df7e5b36..ecc2e5f227 100644 --- a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts +++ b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts @@ -7,6 +7,8 @@ import { calculateAverageAttendance } from "../model/calculate-average-event-att import { NullAttendanceStatusType } from "../model/attendance-status"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormDialogService } from "../../../core/form-dialog/form-dialog.service"; +import { EventNote } from "../model/event-note"; @Component({ selector: "app-attendance-details", @@ -19,7 +21,6 @@ export class AttendanceDetailsComponent @Input() focusedChild: string; @ViewChild("dialogForm", { static: true }) formDialogWrapper; - eventDetailsComponent = { component: NoteDetailsComponent }; eventsColumns: FormFieldConfig[] = [ { id: "date" }, { id: "subject", placeholder: "Event" }, @@ -41,11 +42,15 @@ export class AttendanceDetailsComponent ]; UnknownStatus = NullAttendanceStatusType; - constructor() {} + constructor(private formDialog: FormDialogService) {} onInitFromDynamicConfig(config?: { forChild?: string }) { if (config?.forChild) { this.focusedChild = config.forChild; } } + + showEventDetails(event: EventNote) { + this.formDialog.openDialog(NoteDetailsComponent, event); + } } diff --git a/src/app/child-dev-project/children/children-list/children-list.component.ts b/src/app/child-dev-project/children/children-list/children-list.component.ts index 631d5c856f..e419ac56c9 100644 --- a/src/app/child-dev-project/children/children-list/children-list.component.ts +++ b/src/app/child-dev-project/children/children-list/children-list.component.ts @@ -18,7 +18,7 @@ import { EntityListComponent } from "../../../core/entity-components/entity-list selector: "app-children-list", template: ` diff --git a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts index 712deface1..9c24ba33f1 100644 --- a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts +++ b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts @@ -8,8 +8,8 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Child } from "../../children/model/child"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { ComponentWithConfig } from "../../../core/entity-components/entity-subrecord/component-with-config"; import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormDialogService } from "../../../core/form-dialog/form-dialog.service"; /** * The component that is responsible for listing the Notes that are related to a certain child @@ -24,9 +24,6 @@ export class NotesOfChildComponent implements OnChanges, OnInitDynamicComponent { @Input() child: Child; records: Array = []; - detailsComponent: ComponentWithConfig = { - component: NoteDetailsComponent, - }; columns: FormFieldConfig[] = [ { id: "date" }, @@ -38,7 +35,8 @@ export class NotesOfChildComponent constructor( private childrenService: ChildrenService, - private sessionService: SessionService + private sessionService: SessionService, + private formDialog: FormDialogService ) {} ngOnChanges(changes: SimpleChanges): void { @@ -94,4 +92,8 @@ export class NotesOfChildComponent * @param note note to get color for */ getColor = (note: Note) => note?.getColorForId(this.child.getId()); + + showNoteDetails(note: Note) { + this.formDialog.openDialog(NoteDetailsComponent, note); + } } diff --git a/src/app/child-dev-project/previous-teams/previous-teams.component.html b/src/app/child-dev-project/previous-teams/previous-teams.component.html deleted file mode 100644 index 167daa7c02..0000000000 --- a/src/app/child-dev-project/previous-teams/previous-teams.component.html +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/src/app/child-dev-project/previous-teams/previous-teams.component.spec.ts b/src/app/child-dev-project/previous-teams/previous-teams.component.spec.ts deleted file mode 100644 index c5e01a4b61..0000000000 --- a/src/app/child-dev-project/previous-teams/previous-teams.component.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; - -import { ChildrenService } from "../children/children.service"; -import { EntityMapperService } from "../../core/entity/entity-mapper.service"; -import { ChildrenModule } from "../children/children.module"; -import { RouterTestingModule } from "@angular/router/testing"; -import { ConfirmationDialogModule } from "../../core/confirmation-dialog/confirmation-dialog.module"; -import { SimpleChange } from "@angular/core"; -import { Child } from "../children/model/child"; -import { PreviousTeamsComponent } from "./previous-teams.component"; - -describe("PreviousTeamsComponent", () => { - let component: PreviousTeamsComponent; - let fixture: ComponentFixture; - - let mockChildrenService: jasmine.SpyObj; - let mockEntityMapper: jasmine.SpyObj; - - const testChild = new Child("22"); - - beforeEach( - waitForAsync(() => { - mockChildrenService = jasmine.createSpyObj(["getSchoolsWithRelations"]); - mockChildrenService.getSchoolsWithRelations.and.resolveTo([]); - mockEntityMapper = jasmine.createSpyObj(["loadType"]); - mockEntityMapper.loadType.and.resolveTo([]); - TestBed.configureTestingModule({ - declarations: [PreviousTeamsComponent], - imports: [ - RouterTestingModule, - ChildrenModule, - ConfirmationDialogModule, - ], - providers: [ - { provide: ChildrenService, useValue: mockChildrenService }, - { provide: EntityMapperService, useValue: mockEntityMapper }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(PreviousTeamsComponent); - component = fixture.componentInstance; - component.child = testChild; - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); - - it("it calls children service with id from passed child", (done) => { - spyOn(component, "loadData").and.callThrough(); - mockChildrenService.getSchoolsWithRelations.and.callThrough(); - - component.ngOnChanges({ - child: new SimpleChange(undefined, testChild, false), - }); - - fixture.whenStable().then(() => { - expect(component.loadData).toHaveBeenCalledWith(testChild.getId()); - expect(mockChildrenService.getSchoolsWithRelations).toHaveBeenCalledWith( - testChild.getId() - ); - done(); - }); - }); -}); diff --git a/src/app/child-dev-project/previous-teams/previous-teams.component.ts b/src/app/child-dev-project/previous-teams/previous-teams.component.ts deleted file mode 100644 index 19e8361a2c..0000000000 --- a/src/app/child-dev-project/previous-teams/previous-teams.component.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { - Component, - EventEmitter, - Input, - OnChanges, - OnInit, - Output, - SimpleChanges, -} from "@angular/core"; -import { ChildSchoolRelation } from "../children/model/childSchoolRelation"; -import { ChildrenService } from "../children/children.service"; -import moment from "moment"; -import { Child } from "../children/model/child"; -import { OnInitDynamicComponent } from "../../core/view/dynamic-components/on-init-dynamic-component.interface"; -import { ColumnDescriptionInputType } from "../../core/entity-components/entity-subrecord/column-description-input-type.enum"; -import { ColumnDescription } from "../../core/entity-components/entity-subrecord/column-description"; -import { PanelConfig } from "../../core/entity-components/entity-details/EntityDetailsConfig"; -import { EntityMapperService } from "../../core/entity/entity-mapper.service"; -import { School } from "../schools/model/school"; - -/** - * @deprecated Use PreviousSchoolsComponent with its configuration options instead - */ -@Component({ - selector: "app-previous-schools", - templateUrl: "./previous-teams.component.html", -}) -export class PreviousTeamsComponent - implements OnInit, OnChanges, OnInitDynamicComponent { - @Input() child: Child; - @Output() changedRecordInEntitySubrecord = new EventEmitter(); - records = new Array(); - columns = new Array(); - - constructor( - private childrenService: ChildrenService, - private entityMapper: EntityMapperService - ) {} - - ngOnInit() { - this.initColumnDefinitions(); - } - - ngOnChanges(changes: SimpleChanges) { - if (changes.hasOwnProperty("child")) { - this.loadData(this.child.getId()); - } - } - - onInitFromDynamicConfig(config: PanelConfig) { - this.child = config.entity as Child; - this.loadData(this.child.getId()); - } - - async loadData(id: string) { - if (!this.child.getId() || this.child.getId() === "") { - return; - } - - this.records = await this.childrenService.getSchoolsWithRelations(id); - } - - private async initColumnDefinitions() { - const teams = await this.entityMapper.loadType(School); - const teamsMap = {}; - teams.forEach((s) => (teamsMap[s.getId()] = s.name)); - - this.columns = [ - { - name: "schoolId", - label: "Team", - inputType: ColumnDescriptionInputType.SELECT, - selectValues: teams.map((t) => { - return { value: t.getId(), label: t.name }; - }), - valueFunction: (entity: ChildSchoolRelation) => - teamsMap[entity["schoolId"]], - }, - { - name: "start", - label: "From", - inputType: ColumnDescriptionInputType.DATE, - }, - { - name: "end", - label: "To", - inputType: ColumnDescriptionInputType.DATE, - }, - ]; - } - - generateNewRecordFactory() { - const childId = this.child.getId(); - return () => { - const newPreviousSchool = new ChildSchoolRelation(); - newPreviousSchool.childId = childId; - // last to-date (of first entry in records); if the first entry doesn't have any to-date, lastToDate is set to yesterday - const lastToDate = - this.records.length && this.records[0].end - ? new Date(this.records[0].end) - : new Date(new Date().setDate(new Date().getDate() + -1)); - newPreviousSchool.start = new Date( - lastToDate.setDate(lastToDate.getDate() + 1) - ); // one day after last to-date - newPreviousSchool.end = null; // void date - return newPreviousSchool; - }; - } - - formValidation = (record) => { - const validationResult = { - hasPassedValidation: false, - validationMessage: "", - }; - if (!record.schoolId) { - validationResult.validationMessage = - '"Name" is empty. Please select a team.'; - } else if (moment(record.start).isAfter(record.end, "days")) { - validationResult.validationMessage = - '"To"-date lies before "From"-date. Please enter correct dates.'; - } else { - validationResult.hasPassedValidation = true; - } - return validationResult; - }; -} diff --git a/src/app/child-dev-project/schools/schools-list/schools-list.component.ts b/src/app/child-dev-project/schools/schools-list/schools-list.component.ts index aaedddf89a..bce3a672e6 100644 --- a/src/app/child-dev-project/schools/schools-list/schools-list.component.ts +++ b/src/app/child-dev-project/schools/schools-list/schools-list.component.ts @@ -11,7 +11,7 @@ import { EntityListConfig } from "../../../core/entity-components/entity-list/En selector: "app-schools-list", template: ` {{ listName }}
- (Showing {{ entityDataSource.filteredData.length }} entries) + (Showing {{ entityTable?.recordsDataSource.filteredData.length }} entries)
@@ -50,7 +50,7 @@

{{ listName }}

Add New {{ listName }} [filterConfig]="filter.filterSettings" [(selectedOption)]="filter.selectedOption" [displayAsToggle]="filter.display !== 'dropdown'" - (selectedOptionChange)="onFilterOptionSelected(filter, $event)" + (selectedOptionChange)="filterOptionSelected(filter, $event)" >
@@ -106,40 +106,11 @@

{{ listName }}

- - - - - - - -
- {{ col.placeholder }} - - -
- +
diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index bf255a168c..de96031a1c 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -122,7 +122,7 @@ describe("EntityListComponent", () => { component.listConfig = testConfig; component.entityConstructor = Child; component.ngOnChanges({ - entityList: new SimpleChange(null, component.entityList, false), + entityList: new SimpleChange(null, component.allEntities, false), listConfig: new SimpleChange(null, component.listConfig, false), }); fixture.detectChanges(); @@ -158,9 +158,9 @@ describe("EntityListComponent", () => { const child1 = new Child("dropoutId"); child1.status = "Dropout"; const child2 = new Child("activeId"); - component.entityList = [child1, child2]; + component.allEntities = [child1, child2]; component.ngOnChanges({ - entityList: new SimpleChange(false, component.entityList, false), + entityList: new SimpleChange(false, component.allEntities, false), }); setTimeout(() => { const activeFs = component.filterSelections[0]; @@ -168,7 +168,7 @@ describe("EntityListComponent", () => { expect(component.filterSelections[0].selectedOption).toEqual( clickedOption ); - expect(component.entityList.length).toEqual(2); + expect(component.allEntities.length).toEqual(2); expect(component.entityDataSource.data.length).toEqual(1); expect(component.entityDataSource.data[0]).toEqual(child1); done(); @@ -194,9 +194,9 @@ describe("EntityListComponent", () => { it("should filter a list of children", (done) => { const child1 = new Child("something"); const child2 = new Child("uniqueString"); - component.entityList = [child1, child2]; + component.allEntities = [child1, child2]; component.ngOnChanges({ - entityList: new SimpleChange(false, component.entityList, false), + entityList: new SimpleChange(false, component.allEntities, false), }); setTimeout(() => { component.applyFilter(" UnIquEString "); @@ -210,9 +210,9 @@ describe("EntityListComponent", () => { it("correctly create dropdown and selection filters if values are present", fakeAsync(() => { const child = new Child(); child.religion = "muslim"; - component.entityList = [child]; + component.allEntities = [child]; component.ngOnChanges({ - entityList: new SimpleChange(false, component.entityList, false), + entityList: new SimpleChange(false, component.allEntities, false), }); expect(component.filterSelections.length).toEqual(2); expect( @@ -234,7 +234,7 @@ describe("EntityListComponent", () => { }; component.ngOnChanges({ listConfig: new SimpleChange(false, component.listConfig, false), - entityList: new SimpleChange(false, component.entityList, false), + entityList: new SimpleChange(false, component.allEntities, false), }); expect(component.columnGroups).toEqual([ { name: "default", columns: testConfig.columns.map((c) => c.id) }, @@ -250,7 +250,7 @@ describe("EntityListComponent", () => { it("should apply default sort on first column", async () => { const children = [Child.create("C"), Child.create("A"), Child.create("B")]; component.columnsToDisplay = ["name", "projectNumber"]; - component.entityList = children; + component.allEntities = children; // trigger ngOnChanges for manually updated property component.ngOnChanges({ @@ -269,7 +269,7 @@ describe("EntityListComponent", () => { children[2].admissionDate = new Date(2012, 1, 1); component.columnsToDisplay = ["admissionDate", "name"]; - component.entityList = children; + component.allEntities = children; // define the columns to mark "admissionDate" as a Date value component.columns = [ { @@ -305,7 +305,7 @@ describe("EntityListComponent", () => { children[3].name = "AB"; children[2].name = "Z"; children[1].name = "C"; - component.entityList = children; + component.allEntities = children; component.sort.sort({ id: "name", start: "asc", disableClear: false }); const sortedIds = component.entityDataSource .sortData(children, component.sort) @@ -320,7 +320,7 @@ describe("EntityListComponent", () => { notes[2].category = { id: "2", label: "Z" }; notes[1].category = { id: "3", label: "C" }; component.ngOnInit(); - component.entityList = notes; + component.allEntities = notes; component.sort.sort({ id: "category", start: "asc", disableClear: false }); const sortedIds = component.entityDataSource .sortData(notes, component.sort) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 84cb223d22..f11e26de56 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -1,5 +1,4 @@ import { - AfterViewInit, Component, EventEmitter, Input, @@ -9,9 +8,6 @@ import { SimpleChanges, ViewChild, } from "@angular/core"; -import { MatSort, MatSortable } from "@angular/material/sort"; -import { MatPaginator, PageEvent } from "@angular/material/paginator"; -import { MatTableDataSource } from "@angular/material/table"; import { MediaChange, MediaObserver } from "@angular/flex-layout"; import { ActivatedRoute, Router } from "@angular/router"; import { @@ -28,10 +24,7 @@ import { FilterSelection, FilterSelectionOption, } from "../../filter/filter-selection/filter-selection"; -import { EntityMapperService } from "../../entity/entity-mapper.service"; import { SessionService } from "../../session/session-service/session.service"; -import { User } from "../../user/user"; -import { getUrlWithoutParams } from "../../../utils/utils"; import { ConfigService } from "../../config/config.service"; import { CONFIGURABLE_ENUM_CONFIG_PREFIX, @@ -39,9 +32,8 @@ import { } from "../../configurable-enum/configurable-enum.interface"; import { LoggingService } from "../../logging/logging.service"; import { OperationType } from "../../permissions/entity-permissions.service"; -import { entityListSortingAccessor } from "./sorting-accessor"; -import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { FormFieldConfig } from "../entity-details/form/FormConfig"; +import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; interface FilterComponentSettings { filterSettings: FilterSelection; @@ -63,15 +55,15 @@ interface FilterComponentSettings { styleUrls: ["./entity-list.component.scss"], }) export class EntityListComponent - implements OnChanges, OnInit, AfterViewInit { - @Input() entityList: T[] = []; + implements OnChanges, OnInit { + @Input() allEntities: T[] = []; + filteredEntities: T[] = []; @Input() listConfig: EntityListConfig; @Input() entityConstructor: EntityConstructor; @Output() elementClick = new EventEmitter(); @Output() addNewClick = new EventEmitter(); - @ViewChild(MatSort) sort: MatSort; - @ViewChild(MatPaginator) paginator: MatPaginator; + @ViewChild(EntitySubrecordComponent) entityTable: EntitySubrecordComponent; listName = ""; columns: FormFieldConfig[] = []; @@ -87,29 +79,17 @@ export class EntityListComponent selectedColumnGroup: string = ""; filterSelections: FilterComponentSettings[] = []; - entityDataSource = new MatTableDataSource(); - - user: User; - paginatorPageSize = 10; - paginatorPageIndex = 0; filterString = ""; - // This key is used to save the pagination settings on the user entity - readonly paginatorKey: string; - constructor( private configService: ConfigService, private loggingService: LoggingService, private sessionService: SessionService, private media: MediaObserver, private router: Router, - private activatedRoute: ActivatedRoute, - private entityMapperService: EntityMapperService, - private entitySchemaService: EntitySchemaService - ) { - this.paginatorKey = getUrlWithoutParams(this.router); - } + private activatedRoute: ActivatedRoute + ) { } ngOnInit() { this.media.asObservable().subscribe((change: MediaChange[]) => { @@ -123,20 +103,8 @@ export class EntityListComponent this.displayColumnGroup(this.defaultColumnGroup); break; } - case "lg": - case "xl": { - break; - } } }); - this.user = this.sessionService.getCurrentUser(); - // Use URl as key to save pagination settings - this.paginatorPageSize = - this.user.paginatorSettingsPageSize[this.paginatorKey] || - this.paginatorPageSize; - this.paginatorPageIndex = - this.user.paginatorSettingsPageIndex[this.paginatorKey] || - this.paginatorPageIndex; } ngOnChanges(changes: SimpleChanges): void { @@ -147,111 +115,25 @@ export class EntityListComponent this.filtersConfig = this.listConfig.filters || []; this.displayColumnGroup(this.defaultColumnGroup); } - if (changes.hasOwnProperty("entityList")) { + if (changes.hasOwnProperty("allEntities")) { + this.filteredEntities = this.allEntities; this.initFilterSelections(); - this.initDefaultSort(); } this.loadUrlParams(); } private initColumns() { - const columns = this.listConfig.columns || []; + this.columns = this.listConfig.columns || []; const uniqueColumnIds = new Set(); this.listConfig?.columnGroups?.groups?.forEach((group) => group.columns.forEach((column) => uniqueColumnIds.add(column)) ); uniqueColumnIds.forEach((columnId) => { - if (!columns.some((column) => column.id === columnId)) { - columns.push({ id: columnId }); + if (!this.columns.some((column) => column.id === columnId)) { + this.columns.push({ id: columnId }); } }); - - this.columns = columns.map((column) => { - try { - return this.createColumnDefinitions(column); - } catch (e) { - this.loggingService.warn(`Could not initialize column ${column.id}`); - throw e; - } - }); - } - - private createColumnDefinitions(column: FormFieldConfig): FormFieldConfig { - const propertySchema = this.entityConstructor.schema.get(column.id); - if (!column.view) { - column.view = this.entitySchemaService.getComponent( - propertySchema, - "view" - ); - } - if (!column.placeholder) { - column.placeholder = propertySchema.labelShort || propertySchema.label; - } - return column; - } - - private initDefaultSort() { - if (!this.sort || this.sort.active) { - // do not overwrite existing sort - return; - } - - // initial sorting by first column - const sortBy = this.columnsToDisplay[0]; - let sortDirection = "asc"; - if (this.columns.find((c) => c.id === sortBy)?.view === "DisplayDate") { - // flip default sort order for dates (latest first) - sortDirection = "desc"; - } - - this.sort.sort({ - id: sortBy, - start: sortDirection, - } as MatSortable); - } - - ngAfterViewInit() { - this.entityDataSource.sort = this.sort; - this.entityDataSource.paginator = this.paginator; - // sort data according to it's label, if the data has a label - // (which it has when using configuration enum types) - // otherwise sort by default - this.entityDataSource.sortingDataAccessor = entityListSortingAccessor; - setTimeout(() => { - this.paginator.pageIndex = this.paginatorPageIndex; - this.paginator.page.next({ - pageIndex: this.paginator.pageIndex, - pageSize: this.paginator.pageSize, - length: this.paginator.length, - }); - }); - } - - onPaginateChange(event: PageEvent) { - this.paginatorPageSize = event.pageSize; - this.paginatorPageIndex = event.pageIndex; - this.updateUserPaginationSettings(); - } - - columnGroupClick(columnGroupName: string) { - this.displayColumnGroup(columnGroupName); - this.updateUrl("view", columnGroupName); - } - - applyFilter(filterValue: string) { - filterValue = filterValue.trim(); - filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches - this.entityDataSource.filter = filterValue; - } - - onFilterOptionSelected( - filter: FilterComponentSettings, - selectedOption: string - ) { - filter.selectedOption = selectedOption; - this.applyFilterSelections(); - this.updateUrl(filter.filterSettings.name, selectedOption); } private initColumnGroups(columnGroup?: ColumnGroupsConfig) { @@ -269,24 +151,6 @@ export class EntityListComponent } } - private updateUserPaginationSettings() { - // The PageSize is stored in the database, the PageList is only in memory - const hasChangesToBeSaved = - this.paginatorPageSize !== - this.user.paginatorSettingsPageSize[this.paginatorKey]; - - this.user.paginatorSettingsPageIndex[ - this.paginatorKey - ] = this.paginatorPageIndex; - this.user.paginatorSettingsPageSize[ - this.paginatorKey - ] = this.paginatorPageSize; - - if (hasChangesToBeSaved) { - this.entityMapperService.save(this.user); - } - } - private loadUrlParams() { this.activatedRoute.queryParams.subscribe((params) => { if (params["view"]) { @@ -304,18 +168,28 @@ export class EntityListComponent }); } - private updateUrl(key: string, value: string) { - const params = {}; - params[key] = value; - this.router.navigate([], { - relativeTo: this.activatedRoute, - queryParams: params, - queryParamsHandling: "merge", - }); + columnGroupClick(columnGroupName: string) { + this.displayColumnGroup(columnGroupName); + this.updateUrl("view", columnGroupName); + } + + applyFilter(filterValue: string) { + filterValue = filterValue.trim(); + filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches + this.entityTable.recordsDataSource.filter = filterValue; + } + + filterOptionSelected( + filter: FilterComponentSettings, + selectedOption: string + ) { + filter.selectedOption = selectedOption; + this.applyFilterSelections(); + this.updateUrl(filter.filterSettings.name, selectedOption); } private applyFilterSelections() { - let filteredData = this.entityList; + let filteredData = this.allEntities; this.filterSelections.forEach((f) => { filteredData = filteredData.filter( @@ -323,7 +197,17 @@ export class EntityListComponent ); }); - this.entityDataSource.data = filteredData; + this.filteredEntities = filteredData; + } + + private updateUrl(key: string, value: string) { + const params = {}; + params[key] = value; + this.router.navigate([], { + relativeTo: this.activatedRoute, + queryParams: params, + queryParamsHandling: "merge", + }); } private initFilterSelections() { @@ -359,7 +243,7 @@ export class EntityListComponent config as ConfigurableEnumFilterConfig ); default: { - const options = [...new Set(this.entityList.map((c) => c[config.id]))]; + const options = [...new Set(this.allEntities.map((c) => c[config.id]))]; return FilterSelection.generateOptions(options, config.id); } } @@ -418,4 +302,8 @@ export class EntityListComponent this.selectedColumnGroup = columnGroupName; } } + + getNewRecordFactory(): () => T { + return () => new this.entityConstructor(); + } } diff --git a/src/app/core/entity-components/entity-list/entity-list.module.ts b/src/app/core/entity-components/entity-list/entity-list.module.ts index c8358e5ef7..2906116611 100644 --- a/src/app/core/entity-components/entity-list/entity-list.module.ts +++ b/src/app/core/entity-components/entity-list/entity-list.module.ts @@ -1,9 +1,6 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { EntityListComponent } from "./entity-list.component"; -import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; -import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; -import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; import { MatFormFieldModule } from "@angular/material/form-field"; import { MatSelectModule } from "@angular/material/select"; import { MatIconModule } from "@angular/material/icon"; @@ -19,25 +16,12 @@ import { MatPaginatorModule } from "@angular/material/paginator"; import { FormsModule } from "@angular/forms"; import { AdminModule } from "../../admin/admin.module"; import { ViewModule } from "../../view/view.module"; -import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; import { ListFilterComponent } from "./list-filter/list-filter.component"; import { PermissionsModule } from "../../permissions/permissions.module"; -import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; -import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; -import { DisplayUnitComponent } from "./view-components/display-unit/display-unit.component"; +import { EntitySubrecordModule } from "../entity-subrecord/entity-subrecord.module"; @NgModule({ - declarations: [ - EntityListComponent, - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ListFilterComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], + declarations: [ListFilterComponent, EntityListComponent], imports: [ CommonModule, FormsModule, @@ -57,16 +41,9 @@ import { DisplayUnitComponent } from "./view-components/display-unit/display-uni MatSortModule, MatPaginatorModule, PermissionsModule, + EntitySubrecordModule, ], exports: [EntityListComponent], - entryComponents: [ - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], + entryComponents: [], }) export class EntityListModule {} diff --git a/src/app/core/entity-components/entity-list/entity-list.stories.ts b/src/app/core/entity-components/entity-list/entity-list.stories.ts index ab3d82831c..207088f14a 100644 --- a/src/app/core/entity-components/entity-list/entity-list.stories.ts +++ b/src/app/core/entity-components/entity-list/entity-list.stories.ts @@ -12,6 +12,7 @@ import { EntityMapperService } from "../../entity/entity-mapper.service"; import { Angulartics2Module } from "angulartics2"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; +import { DatePipe } from "@angular/common"; export default { title: "Core/Entity List", @@ -26,6 +27,7 @@ export default { ConfigurableEnumModule, ], providers: [ + DatePipe, { provide: SessionService, useValue: { getCurrentUser: () => new User() }, @@ -48,7 +50,7 @@ const children = new DemoChildGenerator({ count: 20 }).generateEntities(); export const Primary = Template.bind({}); Primary.args = { - entityList: children, + allEntities: children, entityConstructor: Child, listConfig: { title: "Children List", @@ -74,5 +76,22 @@ Primary.args = { }, ], }, + filters: [ + { + id: "isActive", + type: "boolean", + default: "true", + true: "Active Children", + false: "Inactive", + all: "All", + }, + { + id: "center", + label: "Center", + type: "configurable-enum", + enumId: "center", + display: "dropdown", + }, + ], }, }; diff --git a/src/app/core/entity-components/entity-subrecord/component-with-config.ts b/src/app/core/entity-components/entity-subrecord/component-with-config.ts deleted file mode 100644 index 428bb290d6..0000000000 --- a/src/app/core/entity-components/entity-subrecord/component-with-config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Entity } from "../../entity/entity"; -import { ComponentType } from "@angular/cdk/overlay"; -import { ShowsEntity } from "../../form-dialog/shows-entity.interface"; - -/** - * Settings for the popup details view of a EntitySubrecordComponent. - */ -export interface ComponentWithConfig { - /** - * The component to be used for displaying a single Entity instance's details. - */ - component: ComponentType>; - - /** - * Optionally include an object to pass any values into the component, - * which has to implement the OnInitDynamicComponent interface to receive this config. - */ - componentConfig?: any; -} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 9e17df94e7..a3baddcd68 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -10,7 +10,6 @@ import { MatDatepickerModule } from "@angular/material/datepicker"; import { MatSelectModule } from "@angular/material/select"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatIconModule } from "@angular/material/icon"; -import { FormDialogModule } from "../../form-dialog/form-dialog.module"; import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; import { MatSnackBarModule } from "@angular/material/snack-bar"; @@ -20,7 +19,7 @@ import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; import { EntityFormModule } from "../entity-form/entity-form.module"; -import { EntityListModule } from "../entity-list/entity-list.module"; +import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; @NgModule({ declarations: [EntitySubrecordComponent, KeysPipe], @@ -28,7 +27,6 @@ import { EntityListModule } from "../entity-list/entity-list.module"; CommonModule, AlertsModule, MatSnackBarModule, - FormDialogModule, EntityModule, MatTableModule, MatPaginatorModule, @@ -44,7 +42,7 @@ import { EntityListModule } from "../entity-list/entity-list.module"; ViewModule, ReactiveFormsModule, EntityFormModule, - EntityListModule, + ConfirmationDialogModule, ], exports: [EntitySubrecordComponent, KeysPipe], }) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index 608e68088d..6c2ce1f1bd 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -49,7 +49,7 @@ -
+
- (Showing {{ entityTable?.recordsDataSource.filteredData.length }} entries) + (Showing {{ filteredEntities.length }} entries)
diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index 6c2ce1f1bd..a73db0235b 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -19,6 +19,7 @@ mat-cell *matCellDef="let row" (click)="showRecord(row)" + style="cursor: pointer" > */ ngOnChanges(changes: SimpleChanges) { if (changes.hasOwnProperty("columns")) { - this.columnsToDisplay = this.columns.map((e) => e.id); - this.columnsToDisplay.push("actions"); - this.setupTable(); this.initFormGroups(); + this.initDefaultSort(); } else if (changes.hasOwnProperty("records")) { + this.initDefaultSort(); this.initFormGroups(); } } @@ -142,7 +141,6 @@ export class EntitySubrecordComponent ngAfterViewInit() { this.recordsDataSource.sort = this.sort; - this.initDefaultSort(); this.recordsDataSource.paginator = this.paginator; EntitySubrecordComponent.paginatorPageSize.subscribe((newPageSize) => this.updatePagination(newPageSize) diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html index 0b4e824a78..42b409d37c 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html @@ -4,7 +4,7 @@ component: entityBlockComponent, config: { entity: entity, - linkDisabled: false, + linkDisabled: linkDisabled, tooltipDisabled: true } }"> diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 39999f5367..98634fe61d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -13,6 +13,7 @@ import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; }) export class DisplayEntityComponent implements OnInit, OnInitDynamicComponent { @Input() entity: Entity; + @Input() linkDisabled: boolean = false; entityBlockComponent: string; constructor(private entityMapper: EntityMapperService) {} diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html index eb4ecedff4..7865b529f3 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html @@ -1 +1 @@ -
{{ entity[property] ? entity[property] + "%" : "" }}
+
{{ entity[property] + "%" }}
diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 38ff8d408f..6331bbf9c3 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -19,7 +19,6 @@ import { DisplayDateComponent } from "../entity-components/entity-utils/view-com import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; import { ActivityParticipantsSectionComponent } from "../../child-dev-project/attendance/activity-participants-section/activity-participants-section.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; -import { PreviousTeamsComponent } from "../../child-dev-project/previous-teams/previous-teams.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "../../child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component"; import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/dashboard-shortcut-widget/dashboard-shortcut-widget.component"; @@ -50,7 +49,6 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["AttendanceWeekDashboard", AttendanceWeekDashboardComponent], ["ProgressDashboard", ProgressDashboardComponent], ["PreviousSchools", PreviousSchoolsComponent], - ["PreviousTeams", PreviousTeamsComponent], ["Aser", AserComponent], ["GroupedChildAttendance", GroupedChildAttendanceComponent], ["ActivityParticipantsSection", ActivityParticipantsSectionComponent], From 3351ecf64d05606f10c7934332703c0fce35dfa7 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 24 May 2021 11:58:06 +0200 Subject: [PATCH 101/230] working on fixing the unit tests --- .../children-list.component.spec.ts | 16 +- .../previous-schools.component.spec.ts | 22 -- .../schools-list.component.spec.ts | 5 +- .../schools/schools.module.ts | 4 +- .../edit-percentage.component.spec.ts | 19 +- .../entity-list/entity-list.component.spec.ts | 135 +++-------- .../entity-subrecord.module.ts | 2 - .../entity-subrecord.component.spec.ts | 214 +++++++++--------- .../display-percentage.component.spec.ts | 16 +- .../display-unit.component.spec.ts | 17 +- 10 files changed, 177 insertions(+), 273 deletions(-) diff --git a/src/app/child-dev-project/children/children-list/children-list.component.spec.ts b/src/app/child-dev-project/children/children-list/children-list.component.spec.ts index 2727195b42..ef45e461a7 100644 --- a/src/app/child-dev-project/children/children-list/children-list.component.spec.ts +++ b/src/app/child-dev-project/children/children-list/children-list.component.spec.ts @@ -32,15 +32,15 @@ describe("ChildrenListComponent", () => { const routeData: EntityListConfig = { title: "Children List", columns: [ - { component: "DisplayText", title: "PN", id: "projectNumber" }, - { component: "ChildBlock", title: "Name", id: "name" }, - { component: "DisplayDate", title: "DoB", id: "dateOfBirth" }, - { component: "DisplayText", title: "Gender", id: "gender" }, - { component: "DisplayText", title: "Class", id: "schoolClass" }, - { component: "DisplayText", title: "School", id: "schoolId" }, + { view: "DisplayText", placeholder: "PN", id: "projectNumber" }, + { view: "ChildBlock", placeholder: "Name", id: "name" }, + { view: "DisplayDate", placeholder: "DoB", id: "dateOfBirth" }, + { view: "DisplayText", placeholder: "Gender", id: "gender" }, + { view: "DisplayText", placeholder: "Class", id: "schoolClass" }, + { view: "DisplayText", placeholder: "School", id: "schoolId" }, { - component: "RecentAttendanceBlocks", - title: "Attendance (School)", + view: "RecentAttendanceBlocks", + placeholder: "Attendance (School)", id: "school", }, ], diff --git a/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts b/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts index ee08402a28..c84444fb23 100644 --- a/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts +++ b/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts @@ -16,7 +16,6 @@ import { SimpleChange } from "@angular/core"; import { Child } from "../children/model/child"; import { PanelConfig } from "../../core/entity-components/entity-details/EntityDetailsConfig"; import { ChildSchoolRelation } from "../children/model/childSchoolRelation"; -import moment from "moment"; describe("PreviousSchoolsComponent", () => { let component: PreviousSchoolsComponent; @@ -112,25 +111,4 @@ describe("PreviousSchoolsComponent", () => { expect(columnNames).toContain("Class"); expect(columnNames).toContain("Result"); })); - - it("should display errors for invalid fields", () => { - const entry = new ChildSchoolRelation(); - let validation = component.formValidation(entry); - expect(validation.hasPassedValidation).toBeFalse(); - - entry.schoolId = "test school"; - entry.start = new Date(); - entry.end = moment().subtract(1, "week").toDate(); - validation = component.formValidation(entry); - expect(validation.hasPassedValidation).toBeFalse(); - - entry.end = moment().add(1, "week").toDate(); - entry.result = 200; - validation = component.formValidation(entry); - expect(validation.hasPassedValidation).toBeFalse(); - - entry.result = 75; - validation = component.formValidation(entry); - expect(validation.hasPassedValidation).toBeTrue(); - }); }); diff --git a/src/app/child-dev-project/schools/schools-list/schools-list.component.spec.ts b/src/app/child-dev-project/schools/schools-list/schools-list.component.spec.ts index 612d3ae8d5..d3cd0c6486 100644 --- a/src/app/child-dev-project/schools/schools-list/schools-list.component.spec.ts +++ b/src/app/child-dev-project/schools/schools-list/schools-list.component.spec.ts @@ -25,10 +25,7 @@ describe("SchoolsListComponent", () => { const routeData: EntityListConfig = { title: "Schools List", - columns: [ - { component: "DisplayText", title: "Name", id: "name" }, - { component: "DisplayText", title: "Up to class", id: "upToClass" }, - ], + columns: [], columnGroups: { default: "School Info", mobile: "School Info", diff --git a/src/app/child-dev-project/schools/schools.module.ts b/src/app/child-dev-project/schools/schools.module.ts index 61fc096d5e..a06a52247c 100644 --- a/src/app/child-dev-project/schools/schools.module.ts +++ b/src/app/child-dev-project/schools/schools.module.ts @@ -1,5 +1,5 @@ import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; +import { CommonModule, DatePipe } from "@angular/common"; import { SchoolsListComponent } from "./schools-list/schools-list.component"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatButtonModule } from "@angular/material/button"; @@ -75,7 +75,7 @@ import { EntityListModule } from "../../core/entity-components/entity-list/entit ChildrenOverviewComponent, ], exports: [SchoolBlockComponent], - providers: [SchoolsService], + providers: [SchoolsService, DatePipe], entryComponents: [SchoolBlockComponent], }) export class SchoolsModule {} diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts index 7b466de569..ad65acae6a 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts @@ -1,25 +1,30 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { EditPercentageComponent } from './edit-percentage.component'; +import { EditPercentageComponent } from "./edit-percentage.component"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { FormControl } from "@angular/forms"; +import { MatInputModule } from "@angular/material/input"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -describe('EditPercentageComponent', () => { +describe("EditPercentageComponent", () => { let component: EditPercentageComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditPercentageComponent ] - }) - .compileComponents(); + imports: [MatFormFieldModule, MatInputModule, NoopAnimationsModule], + declarations: [EditPercentageComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditPercentageComponent); component = fixture.componentInstance; + component.formControl = new FormControl(); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index de96031a1c..d28f1a93d9 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -5,7 +5,7 @@ import { waitForAsync, } from "@angular/core/testing"; import { EntityListComponent } from "./entity-list.component"; -import { CommonModule } from "@angular/common"; +import { CommonModule, DatePipe } from "@angular/common"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { RouterTestingModule } from "@angular/router/testing"; import { SimpleChange } from "@angular/core"; @@ -18,7 +18,6 @@ import { SessionService } from "../../session/session-service/session.service"; import { ExportDataComponent } from "../../admin/export-data/export-data.component"; import { ChildrenListComponent } from "../../../child-dev-project/children/children-list/children-list.component"; import { Child } from "../../../child-dev-project/children/model/child"; -import { Note } from "../../../child-dev-project/notes/model/note"; import { ConfigService } from "../../config/config.service"; import { LoggingService } from "../../logging/logging.service"; import { BackupService } from "../../admin/services/backup.service"; @@ -33,16 +32,11 @@ describe("EntityListComponent", () => { const testConfig: EntityListConfig = { title: "Children List", columns: [ - { component: "DisplayText", title: "PN", id: "projectNumber" }, - { component: "ChildBlock", title: "Name", id: "name" }, - { component: "DisplayText", title: "Age", id: "age" }, - { component: "DisplayDate", title: "DoB", id: "dateOfBirth" }, - { component: "DisplayText", title: "Gender", id: "gender" }, - { component: "DisplayText", title: "Class", id: "schoolClass" }, - { component: "DisplayEntity", title: "School", id: "schoolId" }, + { view: "DisplayText", placeholder: "Class", id: "schoolClass" }, + { view: "DisplayEntity", placeholder: "School", id: "schoolId" }, { - component: "RecentAttendanceBlocks", - title: "Attendance (School)", + view: "RecentAttendanceBlocks", + placeholder: "Attendance (School)", id: "school", }, ], @@ -91,7 +85,10 @@ describe("EntityListComponent", () => { mockConfigService = jasmine.createSpyObj(["getConfig"]); mockLoggingService = jasmine.createSpyObj(["warn"]); mockEntityMapper = jasmine.createSpyObj(["save"]); - mockEntitySchemaService = jasmine.createSpyObj(["getComponent"]); + mockEntitySchemaService = jasmine.createSpyObj([ + "getComponent", + "registerSchemaDatatype", + ]); TestBed.configureTestingModule({ declarations: [EntityListComponent, ExportDataComponent], @@ -105,6 +102,7 @@ describe("EntityListComponent", () => { ]), ], providers: [ + DatePipe, { provide: SessionService, useValue: mockSessionService }, { provide: ConfigService, useValue: mockConfigService }, { provide: EntityMapperService, useValue: mockEntityMapper }, @@ -164,13 +162,13 @@ describe("EntityListComponent", () => { }); setTimeout(() => { const activeFs = component.filterSelections[0]; - component.onFilterOptionSelected(activeFs, clickedOption); + component.filterOptionSelected(activeFs, clickedOption); expect(component.filterSelections[0].selectedOption).toEqual( clickedOption ); expect(component.allEntities.length).toEqual(2); - expect(component.entityDataSource.data.length).toEqual(1); - expect(component.entityDataSource.data[0]).toEqual(child1); + expect(component.filteredEntities.length).toEqual(1); + expect(component.filteredEntities[0]).toEqual(child1); done(); }); }); @@ -181,7 +179,7 @@ describe("EntityListComponent", () => { const dropoutFs = component.filterSelections[0]; const clickedOption = (testConfig.filters[0] as BooleanFilterConfig).false; const route = fixture.debugElement.injector.get(ActivatedRoute); - component.onFilterOptionSelected(dropoutFs, clickedOption); + component.filterOptionSelected(dropoutFs, clickedOption); const expectedParams = {}; expectedParams[dropoutFs.filterSettings.name] = clickedOption; expect(router.navigate).toHaveBeenCalledWith([], { @@ -200,9 +198,15 @@ describe("EntityListComponent", () => { }); setTimeout(() => { component.applyFilter(" UnIquEString "); - expect(component.entityDataSource.filter).toEqual("uniquestring"); - expect(component.entityDataSource.filteredData.length).toEqual(1); - expect(component.entityDataSource.filteredData[0]).toEqual(child2); + expect(component.entityTable.recordsDataSource.filter).toEqual( + "uniquestring" + ); + expect( + component.entityTable.recordsDataSource.filteredData.length + ).toEqual(1); + expect( + component.entityTable.recordsDataSource.filteredData[0].record + ).toEqual(child2); done(); }); }); @@ -247,87 +251,6 @@ describe("EntityListComponent", () => { expect(component.filterSelections).toEqual([]); }); - it("should apply default sort on first column", async () => { - const children = [Child.create("C"), Child.create("A"), Child.create("B")]; - component.columnsToDisplay = ["name", "projectNumber"]; - component.allEntities = children; - - // trigger ngOnChanges for manually updated property - component.ngOnChanges({ - entityList: new SimpleChange(undefined, children, true), - }); - - expect( - component.entityDataSource._orderData(children).map((c) => c["name"]) - ).toEqual(["A", "B", "C"]); - }); - - it("should apply default sort on first column, ordering dates descending", async () => { - const children = [Child.create("0"), Child.create("1"), Child.create("2")]; - children[0].admissionDate = new Date(2010, 1, 1); - children[1].admissionDate = new Date(2011, 1, 1); - children[2].admissionDate = new Date(2012, 1, 1); - - component.columnsToDisplay = ["admissionDate", "name"]; - component.allEntities = children; - // define the columns to mark "admissionDate" as a Date value - component.columns = [ - { - component: "DisplayDate", - title: "Admission", - id: "admissionDate", - }, - { - component: "DisplayText", - title: "Name", - id: "name", - }, - ]; - - // trigger ngOnChanges for manually updated property - component.ngOnChanges({ - entityList: new SimpleChange(undefined, children, true), - }); - - expect( - component.entityDataSource._orderData(children).map((c) => c["name"]) - ).toEqual(["2", "1", "0"]); - }); - - it("should sort standard objects", () => { - const children = [ - new Child("0"), - new Child("1"), - new Child("2"), - new Child("3"), - ]; - children[0].name = "AA"; - children[3].name = "AB"; - children[2].name = "Z"; - children[1].name = "C"; - component.allEntities = children; - component.sort.sort({ id: "name", start: "asc", disableClear: false }); - const sortedIds = component.entityDataSource - .sortData(children, component.sort) - .map((value) => value.getId()); - expect(sortedIds).toEqual(["0", "3", "1", "2"]); - }); - - it("should sort non-standard objects", () => { - const notes = [new Note("0"), new Note("1"), new Note("2"), new Note("3")]; - notes[0].category = { id: "0", label: "AA" }; - notes[3].category = { id: "1", label: "AB" }; - notes[2].category = { id: "2", label: "Z" }; - notes[1].category = { id: "3", label: "C" }; - component.ngOnInit(); - component.allEntities = notes; - component.sort.sort({ id: "category", start: "asc", disableClear: false }); - const sortedIds = component.entityDataSource - .sortData(notes, component.sort) - .map((note) => note.getId()); - expect(sortedIds).toEqual(["0", "3", "1", "2"]); - }); - it("should add and initialize columns which are only mentioned in the columnGroups", () => { class Test extends Entity { @DatabaseField({ label: "Test Property" }) testProperty: string; @@ -339,8 +262,8 @@ describe("EntityListComponent", () => { columns: [ { id: "anotherColumn", - title: "Predefined Title", - component: "DisplayDate", + placeholder: "Predefined Title", + view: "DisplayDate", }, ], columnGroups: { @@ -358,12 +281,12 @@ describe("EntityListComponent", () => { { title: "Test Property", id: "testProperty", - component: "DisplayText", + view: "DisplayText", }, { title: "Predefined Title", id: "anotherColumn", - component: "DisplayDate", + view: "DisplayDate", }, ]) ); @@ -375,8 +298,8 @@ describe("EntityListComponent", () => { columns: [ { id: "correctColumn", - title: "Predefined Title", - component: "DisplayDate", + placeholder: "Predefined Title", + view: "DisplayDate", }, ], columnGroups: { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index a3baddcd68..2b6119456a 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -14,7 +14,6 @@ import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; import { MatSnackBarModule } from "@angular/material/snack-bar"; import { MatButtonModule } from "@angular/material/button"; -import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; @@ -37,7 +36,6 @@ import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation MatAutocompleteModule, MatIconModule, MatButtonModule, - ConfigurableEnumModule, MatTooltipModule, ViewModule, ReactiveFormsModule, diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index b89e087a04..7fa11a59c5 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -4,13 +4,14 @@ import { EntitySubrecordComponent } from "./entity-subrecord.component"; import { RouterTestingModule } from "@angular/router/testing"; import { EntitySubrecordModule } from "../entity-subrecord.module"; import { Entity } from "../../../entity/entity"; -import { By } from "@angular/platform-browser"; import { SimpleChange } from "@angular/core"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { MatNativeDateModule } from "@angular/material/core"; import { DatePipe, PercentPipe } from "@angular/common"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { ConfigurableEnumValue } from "../../../configurable-enum/configurable-enum.interface"; +import { Child } from "../../../../child-dev-project/children/model/child"; +import { Note } from "../../../../child-dev-project/notes/model/note"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -47,113 +48,6 @@ describe("EntitySubrecordComponent", () => { expect(component).toBeTruthy(); }); - it("displays empty text instead of 'undefined' in textbox", () => { - component.records = [ - Object.assign(new Entity(), { text: "foo", textarea: "foo" }), - Object.assign(new Entity(), { text: undefined, textarea: undefined }), - ]; - - component.columns = [ - { - id: "text", - placeholder: "Test text", - view: "DisplayText", - edit: "EditText", - }, - { - id: "textarea", - placeholder: "Test textarea", - view: "DisplayText", - edit: "EditLongText", - }, - ]; - component.ngOnChanges({ - records: new SimpleChange(undefined, component.records, true), - columns: new SimpleChange(undefined, component.columns, true), - }); - - component.edit(component.recordsDataSource.data[0]); - component.edit(component.recordsDataSource.data[1]); - fixture.detectChanges(); - - const inputFields = fixture.debugElement.queryAll(By.css("input")); - expect(inputFields[0].nativeElement.value).toBe("foo"); - expect(inputFields[1].nativeElement.value).toBe(""); - - const textareaFields = fixture.debugElement.queryAll(By.css("textarea")); - expect(textareaFields[0].nativeElement.value).toBe("foo"); - expect(textareaFields[1].nativeElement.value).toBe(""); - }); - - it("apply formatter function to values in read mode if formatter is given", () => { - component.records = [ - Object.assign(new Entity(), { simple: 0.9, percent: 0.9 }), - ]; - - component.columns = [ - { - id: "simple", - placeholder: "Test simple", - view: "DisplayText", - }, - { - id: "percent", - placeholder: "Test formatted", - view: "DisplayText", - // valueFunction: (entity) => entity["percent"] * 100 + "%", - }, - ]; - component.ngOnChanges({ - records: new SimpleChange(undefined, component.records, true), - columns: new SimpleChange(undefined, component.columns, true), - }); - fixture.detectChanges(); - - const tdColumns = fixture.debugElement.queryAll(By.css("td")); - expect(tdColumns[0].nativeElement.innerText).toBe("0.9"); - expect(tdColumns[1].nativeElement.innerText).toBe("90%"); - }); - - it("formats MONTH, DATE and CONFIGURABLE_ENUM automatically", () => { - component.records = [ - Object.assign(new Entity(), { - month: new Date("2020-01-01"), - day: new Date("2020-01-23"), - configurableEnum: { label: "enum label", id: "enumId" }, - }), - ]; - - component.columns = [ - { - id: "month", - placeholder: "Test month", - view: "DisplayDate", - additional: "YYYY-MM", - }, - { - id: "day", - placeholder: "Test day", - view: "DisplayDate", - additional: "YYYY-MM-dd", - }, - { - id: "configurableEnum", - placeholder: "Test Configurable Enum", - view: "DisplayConfigurableEnum", - }, - ]; - component.ngOnChanges({ - records: new SimpleChange(undefined, component.records, true), - columns: new SimpleChange(undefined, component.columns, true), - }); - fixture.detectChanges(); - - const tdColumns = fixture.debugElement.queryAll(By.css("td")); - expect(tdColumns[0].nativeElement.innerText).toBe("2020-01"); - expect(tdColumns[1].nativeElement.innerText).toBe("2020-01-23"); - expect(tdColumns[2].nativeElement.innerText).toBe("enum label"); - }); - it("should sort enums by the label", () => { class Test extends Entity { public enumValue: ConfigurableEnumValue; @@ -190,4 +84,108 @@ describe("EntitySubrecordComponent", () => { .map((row) => row.record); expect(sortedData).toEqual([first, second, third]); }); + + it("should apply default sort on first column", async () => { + const children = [Child.create("C"), Child.create("A"), Child.create("B")]; + component.columnsToDisplay = ["name", "projectNumber"]; + component.records = children; + // trigger ngOnChanges for manually updated property + component.ngOnChanges({ + records: new SimpleChange(undefined, children, true), + }); + + const sortedChildren = component.recordsDataSource + .sortData( + children.map((child) => { + return { record: child }; + }), + component.sort + ) + .map((c) => c.record["name"]); + + expect(sortedChildren).toEqual(["A", "B", "C"]); + }); + + it("should apply default sort on first column, ordering dates descending", async () => { + const children = [Child.create("0"), Child.create("1"), Child.create("2")]; + children[0].admissionDate = new Date(2010, 1, 1); + children[1].admissionDate = new Date(2011, 1, 1); + children[2].admissionDate = new Date(2012, 1, 1); + + component.columnsToDisplay = ["admissionDate", "name"]; + component.records = children; + // define the columns to mark "admissionDate" as a Date value + component.columns = [ + { + view: "DisplayDate", + placeholder: "Admission", + id: "admissionDate", + }, + { + view: "DisplayText", + placeholder: "Name", + id: "name", + }, + ]; + + component.ngOnChanges({ + entityList: new SimpleChange(undefined, children, true), + }); + + const sortedChildren = component.recordsDataSource + ._orderData( + children.map((child) => { + return { record: child }; + }) + ) + .map((c) => c.record["name"]); + + expect(sortedChildren).toEqual(["2", "1", "0"]); + }); + + it("should sort standard objects", () => { + const children = [ + new Child("0"), + new Child("1"), + new Child("2"), + new Child("3"), + ]; + children[0].name = "AA"; + children[3].name = "AB"; + children[2].name = "Z"; + children[1].name = "C"; + component.records = children; + component.sort.sort({ id: "name", start: "asc", disableClear: false }); + + const sortedIds = component.recordsDataSource + .sortData( + children.map((child) => { + return { record: child }; + }), + component.sort + ) + .map((c) => c.record.getId()); + + expect(sortedIds).toEqual(["0", "3", "1", "2"]); + }); + + it("should sort non-standard objects", () => { + const notes = [new Note("0"), new Note("1"), new Note("2"), new Note("3")]; + notes[0].category = { id: "0", label: "AA" }; + notes[3].category = { id: "1", label: "AB" }; + notes[2].category = { id: "2", label: "Z" }; + notes[1].category = { id: "3", label: "C" }; + component.records = notes; + component.sort.sort({ id: "category", start: "asc", disableClear: false }); + const sortedIds = component.recordsDataSource + .sortData( + notes.map((note) => { + return { record: note }; + }), + component.sort + ) + .map((note) => note.record.getId()); + + expect(sortedIds).toEqual(["0", "3", "1", "2"]); + }); }); diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts index 7d65b60bca..2846708518 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts @@ -1,25 +1,27 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { DisplayPercentageComponent } from './display-percentage.component'; +import { DisplayPercentageComponent } from "./display-percentage.component"; +import { ChildSchoolRelation } from "../../../../../child-dev-project/children/model/childSchoolRelation"; -describe('DisplayPercentageComponent', () => { +describe("DisplayPercentageComponent", () => { let component: DisplayPercentageComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DisplayPercentageComponent ] - }) - .compileComponents(); + declarations: [DisplayPercentageComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(DisplayPercentageComponent); component = fixture.componentInstance; + component.entity = new ChildSchoolRelation(); + component.property = "result"; fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); diff --git a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts index f5e9d40121..6c3886901c 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts @@ -1,25 +1,28 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { DisplayUnitComponent } from './display-unit.component'; +import { DisplayUnitComponent } from "./display-unit.component"; +import { HealthCheck } from "../../../../../child-dev-project/health-checkup/model/health-check"; -describe('DisplayUnitComponent', () => { +describe("DisplayUnitComponent", () => { let component: DisplayUnitComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DisplayUnitComponent ] - }) - .compileComponents(); + declarations: [DisplayUnitComponent], + }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(DisplayUnitComponent); component = fixture.componentInstance; + component.entity = new HealthCheck(); + component.property = "height"; + component.unit = "cm"; fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); }); From d20032d8cc17cc259e477763c59cb4a347d81a28 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 24 May 2021 13:37:46 +0200 Subject: [PATCH 102/230] fixed tests --- .../entity-form/entity-form.service.ts | 36 ++++-- .../entity-list/entity-list.component.spec.ts | 103 +++++------------- .../entity-list/entity-list.component.ts | 9 +- .../entity-subrecord.component.spec.ts | 27 ++++- .../entity-subrecord.component.ts | 21 ++-- .../display-entity.component.ts | 1 + 6 files changed, 99 insertions(+), 98 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index d5fec31eec..e7b11cc186 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -21,22 +21,34 @@ export class EntityFormService { forTable = false ) { formFields.forEach((formField) => { - const propertySchema = entity.getSchema().get(formField.id); - formField.input = - formField.input || - this.entitySchemaService.getComponent(propertySchema, "edit"); - formField.view = - formField.view || - this.entitySchemaService.getComponent(propertySchema, "view"); - formField.placeholder = formField.placeholder || propertySchema.label; - if (forTable) { - formField.forTable = true; - formField.placeholder = - propertySchema?.labelShort || formField.placeholder; + try { + this.addFormFields(formField, entity, forTable); + } catch (err) { + console.log(`Could not create form config for ${formField.id}: ${err}`); + throw new Error( + `Could not create form config for ${formField.id}: ${err}` + ); } }); } + private addFormFields(formField: FormFieldConfig, entity: Entity, forTable) { + const propertySchema = entity.getSchema().get(formField.id); + formField.input = + formField.input || + this.entitySchemaService.getComponent(propertySchema, "edit"); + formField.view = + formField.view || + this.entitySchemaService.getComponent(propertySchema, "view"); + console.log("form", formField.id); + formField.placeholder = formField.placeholder || propertySchema.label; + if (forTable) { + formField.forTable = true; + formField.placeholder = + propertySchema?.labelShort || formField.placeholder; + } + } + public createFormGroup( formFields: FormFieldConfig[], entity: Entity diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index d28f1a93d9..b40ce2d0b8 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -25,6 +25,8 @@ import { EntityListModule } from "./entity-list.module"; import { Angulartics2Module } from "angulartics2"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { DatabaseField } from "../../entity/database-field.decorator"; +import { ReactiveFormsModule } from "@angular/forms"; +import { AttendanceService } from "../../../child-dev-project/attendance/attendance.service"; describe("EntityListComponent", () => { let component: EntityListComponent; @@ -32,12 +34,14 @@ describe("EntityListComponent", () => { const testConfig: EntityListConfig = { title: "Children List", columns: [ - { view: "DisplayText", placeholder: "Class", id: "schoolClass" }, - { view: "DisplayEntity", placeholder: "School", id: "schoolId" }, + { view: "DisplayText", placeholder: "Age", id: "age" }, { view: "RecentAttendanceBlocks", placeholder: "Attendance (School)", id: "school", + additional: { + filterByActivityType: "SCHOOL_CLASS", + }, }, ], columnGroups: { @@ -46,11 +50,11 @@ describe("EntityListComponent", () => { groups: [ { name: "Basic Info", - columns: ["projectNumber", "name", "age"], + columns: ["projectNumber", "name", "age", "gender", "religion"], }, { name: "School Info", - columns: ["name", "schoolClass", "schoolId", "school"], + columns: ["name", "age", "school"], }, ], }, @@ -77,6 +81,7 @@ describe("EntityListComponent", () => { let mockSessionService: jasmine.SpyObj; let mockEntityMapper: jasmine.SpyObj; let mockEntitySchemaService: jasmine.SpyObj; + let mockAttendanceService: jasmine.SpyObj; beforeEach( waitForAsync(() => { @@ -89,6 +94,14 @@ describe("EntityListComponent", () => { "getComponent", "registerSchemaDatatype", ]); + mockAttendanceService = jasmine.createSpyObj([ + "getActivitiesForChild", + "getAllActivityAttendancesForPeriod", + ]); + mockAttendanceService.getActivitiesForChild.and.resolveTo([]); + mockAttendanceService.getAllActivityAttendancesForPeriod.and.resolveTo( + [] + ); TestBed.configureTestingModule({ declarations: [EntityListComponent, ExportDataComponent], @@ -97,6 +110,7 @@ describe("EntityListComponent", () => { NoopAnimationsModule, EntityListModule, Angulartics2Module.forRoot(), + ReactiveFormsModule, RouterTestingModule.withRoutes([ { path: "child", component: ChildrenListComponent }, ]), @@ -109,6 +123,7 @@ describe("EntityListComponent", () => { { provide: LoggingService, useValue: mockLoggingService }, { provide: BackupService, useValue: {} }, { provide: EntitySchemaService, useValue: mockEntitySchemaService }, + { provide: AttendanceService, useValue: mockAttendanceService }, ], }).compileComponents(); }) @@ -120,7 +135,7 @@ describe("EntityListComponent", () => { component.listConfig = testConfig; component.entityConstructor = Child; component.ngOnChanges({ - entityList: new SimpleChange(null, component.allEntities, false), + allEntities: new SimpleChange(null, component.allEntities, false), listConfig: new SimpleChange(null, component.listConfig, false), }); fixture.detectChanges(); @@ -157,9 +172,7 @@ describe("EntityListComponent", () => { child1.status = "Dropout"; const child2 = new Child("activeId"); component.allEntities = [child1, child2]; - component.ngOnChanges({ - entityList: new SimpleChange(false, component.allEntities, false), - }); + component.ngOnChanges({ allEntities: null }); setTimeout(() => { const activeFs = component.filterSelections[0]; component.filterOptionSelected(activeFs, clickedOption); @@ -174,12 +187,15 @@ describe("EntityListComponent", () => { }); it("should navigate to the correct url params when clicking a filter", () => { - const router = fixture.debugElement.injector.get(Router); + const router = TestBed.inject(Router); spyOn(router, "navigate"); + console.log("component", component.filterSelections); const dropoutFs = component.filterSelections[0]; const clickedOption = (testConfig.filters[0] as BooleanFilterConfig).false; - const route = fixture.debugElement.injector.get(ActivatedRoute); + const route = TestBed.inject(ActivatedRoute); + component.filterOptionSelected(dropoutFs, clickedOption); + const expectedParams = {}; expectedParams[dropoutFs.filterSettings.name] = clickedOption; expect(router.navigate).toHaveBeenCalledWith([], { @@ -189,35 +205,11 @@ describe("EntityListComponent", () => { }); }); - it("should filter a list of children", (done) => { - const child1 = new Child("something"); - const child2 = new Child("uniqueString"); - component.allEntities = [child1, child2]; - component.ngOnChanges({ - entityList: new SimpleChange(false, component.allEntities, false), - }); - setTimeout(() => { - component.applyFilter(" UnIquEString "); - expect(component.entityTable.recordsDataSource.filter).toEqual( - "uniquestring" - ); - expect( - component.entityTable.recordsDataSource.filteredData.length - ).toEqual(1); - expect( - component.entityTable.recordsDataSource.filteredData[0].record - ).toEqual(child2); - done(); - }); - }); - it("correctly create dropdown and selection filters if values are present", fakeAsync(() => { const child = new Child(); child.religion = "muslim"; component.allEntities = [child]; - component.ngOnChanges({ - entityList: new SimpleChange(false, component.allEntities, false), - }); + component.ngOnChanges({ allEntities: null }); expect(component.filterSelections.length).toEqual(2); expect( component.filterSelections @@ -238,7 +230,7 @@ describe("EntityListComponent", () => { }; component.ngOnChanges({ listConfig: new SimpleChange(false, component.listConfig, false), - entityList: new SimpleChange(false, component.allEntities, false), + allEntities: new SimpleChange(false, component.allEntities, false), }); expect(component.columnGroups).toEqual([ { name: "default", columns: testConfig.columns.map((c) => c.id) }, @@ -276,43 +268,8 @@ describe("EntityListComponent", () => { component.ngOnChanges({ listConfig: null }); - expect(component.columns).toEqual( - jasmine.arrayWithExactContents([ - { - title: "Test Property", - id: "testProperty", - view: "DisplayText", - }, - { - title: "Predefined Title", - id: "anotherColumn", - view: "DisplayDate", - }, - ]) + expect(component.columns.map((col) => col.id)).toEqual( + jasmine.arrayWithExactContents(["testProperty", "anotherColumn"]) ); }); - - it("should log an error when the column definition can not be initialized", () => { - component.listConfig = { - title: "", - columns: [ - { - id: "correctColumn", - placeholder: "Predefined Title", - view: "DisplayDate", - }, - ], - columnGroups: { - groups: [ - { - name: "Invalid Group", - columns: ["correctColumn", "notExistentColumn"], - }, - ], - }, - }; - - expect(() => component.ngOnChanges({ listConfig: null })).toThrowError(); - expect(mockLoggingService.warn).toHaveBeenCalled(); - }); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index f11e26de56..04ec0a42cc 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -89,7 +89,7 @@ export class EntityListComponent private media: MediaObserver, private router: Router, private activatedRoute: ActivatedRoute - ) { } + ) {} ngOnInit() { this.media.asObservable().subscribe((change: MediaChange[]) => { @@ -116,6 +116,7 @@ export class EntityListComponent this.displayColumnGroup(this.defaultColumnGroup); } if (changes.hasOwnProperty("allEntities")) { + console.log("called", this.allEntities); this.filteredEntities = this.allEntities; this.initFilterSelections(); } @@ -174,6 +175,12 @@ export class EntityListComponent } applyFilter(filterValue: string) { + console.log( + "filtering", + this.entityTable.records, + this.entityTable.columns, + this.entityTable.columnsToDisplay + ); filterValue = filterValue.trim(); filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches this.entityTable.recordsDataSource.filter = filterValue; diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 7fa11a59c5..966ed302f3 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -12,6 +12,7 @@ import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { ConfigurableEnumValue } from "../../../configurable-enum/configurable-enum.interface"; import { Child } from "../../../../child-dev-project/children/model/child"; import { Note } from "../../../../child-dev-project/notes/model/note"; +import { AlertService } from "../../../alerts/alert.service"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -129,8 +130,9 @@ describe("EntitySubrecordComponent", () => { ]; component.ngOnChanges({ - entityList: new SimpleChange(undefined, children, true), + records: new SimpleChange(undefined, children, true), }); + fixture.detectChanges(); const sortedChildren = component.recordsDataSource ._orderData( @@ -154,7 +156,7 @@ describe("EntitySubrecordComponent", () => { children[3].name = "AB"; children[2].name = "Z"; children[1].name = "C"; - component.records = children; + component.ngOnChanges({ records: null }); component.sort.sort({ id: "name", start: "asc", disableClear: false }); const sortedIds = component.recordsDataSource @@ -175,7 +177,8 @@ describe("EntitySubrecordComponent", () => { notes[3].category = { id: "1", label: "AB" }; notes[2].category = { id: "2", label: "Z" }; notes[1].category = { id: "3", label: "C" }; - component.records = notes; + component.ngOnChanges({ records: null }); + component.sort.sort({ id: "category", start: "asc", disableClear: false }); const sortedIds = component.recordsDataSource .sortData( @@ -188,4 +191,22 @@ describe("EntitySubrecordComponent", () => { expect(sortedIds).toEqual(["0", "3", "1", "2"]); }); + + it("should log an error when the column definition can not be initialized", () => { + const alertService = TestBed.inject(AlertService); + spyOn(alertService, "addWarning"); + component.records = [new Child()]; + component.columns = [ + { + id: "correctColumn", + placeholder: "Predefined Title", + view: "DisplayDate", + }, + { id: "notExistentColumn" }, + ]; + + component.ngOnChanges({ columns: null }); + + expect(alertService.addWarning).toHaveBeenCalled(); + }); }); diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index bc363062e3..ba65a3a177 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -131,15 +131,21 @@ export class EntitySubrecordComponent }; }); if (this.records.length > 0) { - this.entityFormService.extendFormFieldConfig( - this.columns, - this.records[0], - true - ); + try { + this.entityFormService.extendFormFieldConfig( + this.columns, + this.records[0], + true + ); + } catch (err) { + this.alertService.addWarning(`Error creating form definitions: ${err}`); + } } } - ngAfterViewInit() { + ngAfterViewInit() {} + + private initDefaultSort() { this.recordsDataSource.sort = this.sort; this.recordsDataSource.paginator = this.paginator; EntitySubrecordComponent.paginatorPageSize.subscribe((newPageSize) => @@ -149,9 +155,6 @@ export class EntitySubrecordComponent row: TableRow, id: string ) => entityListSortingAccessor(row.record, id); - } - - private initDefaultSort() { if (!this.sort || this.sort.active) { // do not overwrite existing sort return; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 98634fe61d..2e2085f2db 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -27,6 +27,7 @@ export class DisplayEntityComponent implements OnInit, OnInitDynamicComponent { } async onInitFromDynamicConfig(config: ViewPropertyConfig) { + console.log("called", config); const type = config.config || config.entity.getSchema().get(config.id).ext; const entityConstructor = ENTITY_MAP.get(type); if (!entityConstructor) { From f491e4a46b84caecd85fb5ab7877769ec0484917 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 24 May 2021 13:48:51 +0200 Subject: [PATCH 103/230] fixed lint errors --- src/app/child-dev-project/aser/model/aser.ts | 34 +++++++++++++++---- .../educational-material.component.ts | 2 +- .../model/educational-material.ts | 13 ++++--- .../form/form.component.spec.ts | 6 +--- .../edit-configurable-enum.component.ts | 4 ++- ...isplay-configurable-enum.component.spec.ts | 2 +- .../display-text/display-text.component.ts | 2 +- 7 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index 98ff4afc89..cabc8b29ef 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -43,23 +43,43 @@ export class Aser extends Entity { return true; } return level === this.ReadingLevels[4]; - } + static isMathPassedOrNA(level: string) { if (level === "" || level === undefined) { // not applicable return true; } return level === this.MathLevels[4]; - } @DatabaseField() child: string; // id of Child entity - @DatabaseField({ label: "Date", ext: Aser.ReadingLevels }) date: Date = new Date(); - @DatabaseField({ label: "Hindi", editComponent: "EditSelectable", ext: Aser.ReadingLevels }) hindi: string = ""; - @DatabaseField({ label: "Bengali", editComponent: "EditSelectable", ext: Aser.ReadingLevels }) bengali: string = ""; - @DatabaseField({ label: "English", editComponent: "EditSelectable", ext: Aser.ReadingLevels }) english: string = ""; - @DatabaseField({ label: "Math", editComponent: "EditSelectable", ext: Aser.MathLevels }) math: string = ""; + @DatabaseField({ label: "Date", ext: Aser.ReadingLevels }) + date: Date = new Date(); + @DatabaseField({ + label: "Hindi", + editComponent: "EditSelectable", + ext: Aser.ReadingLevels, + }) + hindi: string = ""; + @DatabaseField({ + label: "Bengali", + editComponent: "EditSelectable", + ext: Aser.ReadingLevels, + }) + bengali: string = ""; + @DatabaseField({ + label: "English", + editComponent: "EditSelectable", + ext: Aser.ReadingLevels, + }) + english: string = ""; + @DatabaseField({ + label: "Math", + editComponent: "EditSelectable", + ext: Aser.MathLevels, + }) + math: string = ""; @DatabaseField({ label: "Remarks" }) remarks: string = ""; getWarningLevel(): WarningLevel { diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index 893a7bc8ce..e38742d28c 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -20,7 +20,7 @@ export class EducationalMaterialComponent materialTypes = EducationalMaterial.MATERIAL_ALL; columns: FormFieldConfig[] = [ - { id: "date" }, + { id: "date" }, { id: "materialType" }, { id: "materialAmount" }, { id: "description" }, diff --git a/src/app/child-dev-project/educational-material/model/educational-material.ts b/src/app/child-dev-project/educational-material/model/educational-material.ts index 3268bb3cde..39d6c92074 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.ts @@ -60,10 +60,15 @@ export class EducationalMaterial extends Entity { ); @DatabaseField() child: string; // id of Child entity - @DatabaseField({ label: "Date"}) date: Date; - @DatabaseField({ label: "Material", editComponent: "EditSelectable", ext: EducationalMaterial.MATERIAL_ALL}) materialType = ""; - @DatabaseField({ label: "Amount"}) materialAmount: number; - @DatabaseField({ label: "Description"}) description = ""; + @DatabaseField({ label: "Date" }) date: Date; + @DatabaseField({ + label: "Material", + editComponent: "EditSelectable", + ext: EducationalMaterial.MATERIAL_ALL, + }) + materialType = ""; + @DatabaseField({ label: "Amount" }) materialAmount: number; + @DatabaseField({ label: "Description" }) description = ""; public getColor() { if (EducationalMaterial.MATERIAL_STATIONARIES.includes(this.materialType)) { diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index 4537c4c8cb..c355d3409c 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -1,8 +1,4 @@ -import { - ComponentFixture, - TestBed, - waitForAsync, -} from "@angular/core/testing"; +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { FormComponent } from "./form.component"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { RouterTestingModule } from "@angular/router/testing"; diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts index 385adf882e..85431f66bf 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts @@ -9,8 +9,10 @@ import { ConfigurableEnumValue } from "../../../../configurable-enum/configurabl }) export class EditConfigurableEnumComponent extends EditComponent { enumId: string; + onInitFromDynamicConfig(config: EditPropertyConfig) { super.onInitFromDynamicConfig(config); - this.enumId = config.formFieldConfig.additional || config.propertySchema.innerDataType; + this.enumId = + config.formFieldConfig.additional || config.propertySchema.innerDataType; } } diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts index 1a137e5ef5..6b45cb75a0 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts @@ -5,7 +5,7 @@ import { Note } from "../../../../../child-dev-project/notes/model/note"; describe("DisplayConfigurableEnumComponent", () => { let component: DisplayConfigurableEnumComponent; let fixture: ComponentFixture; - let note = new Note(); + const note = new Note(); note.category = { id: "testCategory", label: "Test Category" }; beforeEach( diff --git a/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts index da9e5c6ec7..6b6858ecec 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts @@ -8,4 +8,4 @@ import { ViewComponent } from "../view-component"; selector: "app-display-text", template: `{{ entity[property] }}`, }) -export class DisplayTextComponent extends ViewComponent{} +export class DisplayTextComponent extends ViewComponent {} From e616f7452ca823c9fe8b3a3eb78ccedff562cfa8 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 08:18:06 +0200 Subject: [PATCH 104/230] removed duplicate input definition --- src/app/app.module.ts | 4 ---- .../entity-details/form/FormConfig.ts | 6 ------ .../entity-details/form/form.component.html | 2 +- .../entity-form/entity-form.service.ts | 5 ++--- .../entity-list/entity-list.component.spec.ts | 1 - .../entity-list/entity-list.component.ts | 7 ------- .../entity-subrecord.component.html | 4 ++-- .../entity-subrecord/entity-subrecord.component.ts | 14 +++++++++----- .../display-entity/display-entity.component.ts | 1 - .../core/entity/schema-datatypes/datatype-month.ts | 1 - 10 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6bdf39fc1b..307682ba3c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -42,7 +42,6 @@ import { AdminModule } from "./core/admin/admin.module"; import { EntityModule } from "./core/entity/entity.module"; import { HelpModule } from "./core/help/help.module"; import { DemoDataModule } from "./core/demo-data/demo-data.module"; -import { MatNativeDateModule } from "@angular/material/core"; import { LoggingErrorHandler } from "./core/logging/logging-error-handler"; import { DemoChildGenerator } from "./child-dev-project/children/demo-data-generators/demo-child-generator.service"; import { DemoSchoolGenerator } from "./child-dev-project/schools/demo-school-generator.service"; @@ -71,7 +70,6 @@ import { ConfigurableEnumModule } from "./core/configurable-enum/configurable-en import { ConfigModule } from "./core/config/config.module"; import { DemoActivityEventsGeneratorService } from "./child-dev-project/attendance/demo-data/demo-activity-events-generator.service"; import { ReportingModule } from "./features/reporting/reporting.module"; -import { MatFormFieldModule } from "@angular/material/form-field"; import { DashboardShortcutWidgetModule } from "./core/dashboard-shortcut-widget/dashboard-shortcut-widget.module"; import { HistoricalDataModule } from "./features/historical-data/historical-data.module"; @@ -115,7 +113,6 @@ import { HistoricalDataModule } from "./features/historical-data/historical-data AdminModule, FontAwesomeIconsModule, HelpModule, - MatNativeDateModule, EntitySubrecordModule, EntityListModule, EntityDetailsModule, @@ -142,7 +139,6 @@ import { HistoricalDataModule } from "./features/historical-data/historical-data ...DemoUserGeneratorService.provider(), ]), AttendanceModule, - MatFormFieldModule, DashboardShortcutWidgetModule, HistoricalDataModule, ], diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-details/form/FormConfig.ts index dff1517ecf..1ccc2d0a64 100644 --- a/src/app/core/entity-components/entity-details/form/FormConfig.ts +++ b/src/app/core/entity-components/entity-details/form/FormConfig.ts @@ -3,12 +3,6 @@ export interface FormConfig { } export interface FormFieldConfig { - /** - * The input type for the form. - * Available options: "photo", "text", "textarea", "checkbox", "age", "select", "configurable-enum-select", "datepicker" - */ - input?: string; - view?: string; edit?: string; diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-details/form/form.component.html index 527d0b4953..d99eb79b87 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-details/form/form.component.html @@ -8,7 +8,7 @@
{ it("should navigate to the correct url params when clicking a filter", () => { const router = TestBed.inject(Router); spyOn(router, "navigate"); - console.log("component", component.filterSelections); const dropoutFs = component.filterSelections[0]; const clickedOption = (testConfig.filters[0] as BooleanFilterConfig).false; const route = TestBed.inject(ActivatedRoute); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 04ec0a42cc..dc5941401f 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -116,7 +116,6 @@ export class EntityListComponent this.displayColumnGroup(this.defaultColumnGroup); } if (changes.hasOwnProperty("allEntities")) { - console.log("called", this.allEntities); this.filteredEntities = this.allEntities; this.initFilterSelections(); } @@ -175,12 +174,6 @@ export class EntityListComponent } applyFilter(filterValue: string) { - console.log( - "filtering", - this.entityTable.records, - this.entityTable.columns, - this.entityTable.columnsToDisplay - ); filterValue = filterValue.trim(); filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches this.entityTable.recordsDataSource.filter = filterValue; diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index a73db0235b..f618ca6d67 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -22,7 +22,7 @@ style="cursor: pointer" > // initial sorting by first column const sortBy = this.columnsToDisplay[0]; + const sortByColumn = this.columns.find((c) => c.id === sortBy); let sortDirection = "asc"; - if (this.columns.find((c) => c.id === sortBy)?.view === "DisplayDate") { + if ( + sortByColumn?.view === "DisplayDate" || + sortByColumn.edit === "EditDate" + ) { // flip default sort order for dates (latest first) sortDirection = "desc"; } diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 2e2085f2db..98634fe61d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -27,7 +27,6 @@ export class DisplayEntityComponent implements OnInit, OnInitDynamicComponent { } async onInitFromDynamicConfig(config: ViewPropertyConfig) { - console.log("called", config); const type = config.config || config.entity.getSchema().get(config.id).ext; const entityConstructor = ENTITY_MAP.get(type); if (!entityConstructor) { diff --git a/src/app/core/entity/schema-datatypes/datatype-month.ts b/src/app/core/entity/schema-datatypes/datatype-month.ts index 6b14f6d81f..26c7a554e5 100644 --- a/src/app/core/entity/schema-datatypes/datatype-month.ts +++ b/src/app/core/entity/schema-datatypes/datatype-month.ts @@ -47,7 +47,6 @@ export const monthEntitySchemaDatatype: EntitySchemaDatatype = { .replace(/-(\d)$/g, "-0$1"); const date = new Date(value); if (Number.isNaN(date.getTime())) { - console.log("value aus datatype-month.ts: " + value); throw new Error("failed to convert data to Date object: " + value); } return date; From 025d3954c8955fafce04c23bd5cd3be0732521b2 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 09:25:38 +0200 Subject: [PATCH 105/230] using schema information to create filters --- .../roll-call/roll-call.component.ts | 7 +- .../attendance-status-select.component.ts | 7 +- .../attendance/attendance.service.ts | 5 +- .../attendance/model/attendance-status.ts | 8 +- .../demo-data/demo-note-generator.service.ts | 7 +- .../notes/model/interaction-type.interface.ts | 8 +- .../notes/model/note.spec.ts | 4 +- src/app/core/config/config-fix.ts | 11 +- .../entity-details.component.ts | 2 +- .../edit-single-entity.component.ts | 2 +- .../entity-list/entity-list.component.ts | 116 ++---------------- 11 files changed, 41 insertions(+), 136 deletions(-) diff --git a/src/app/child-dev-project/attendance/add-day-attendance/roll-call/roll-call.component.ts b/src/app/child-dev-project/attendance/add-day-attendance/roll-call/roll-call.component.ts index ff084ac28c..e0b3de57dd 100644 --- a/src/app/child-dev-project/attendance/add-day-attendance/roll-call/roll-call.component.ts +++ b/src/app/child-dev-project/attendance/add-day-attendance/roll-call/roll-call.component.ts @@ -7,7 +7,10 @@ import { import { Note } from "../../../notes/model/note"; import { EventAttendance } from "../../model/event-attendance"; import { ConfigService } from "../../../../core/config/config.service"; -import { ConfigurableEnumConfig } from "../../../../core/configurable-enum/configurable-enum.interface"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumConfig, +} from "../../../../core/configurable-enum/configurable-enum.interface"; import { EntityMapperService } from "../../../../core/entity/entity-mapper.service"; import { Child } from "../../../children/model/child"; import { LoggingService } from "../../../../core/logging/logging.service"; @@ -65,7 +68,7 @@ export class RollCallComponent implements OnInit { private loadAttendanceStatusTypes() { this.availableStatus = this.configService.getConfig< ConfigurableEnumConfig - >(ATTENDANCE_STATUS_CONFIG_ID); + >(CONFIGURABLE_ENUM_CONFIG_PREFIX + ATTENDANCE_STATUS_CONFIG_ID); } private async loadParticipants() { diff --git a/src/app/child-dev-project/attendance/attendance-status-select/attendance-status-select.component.ts b/src/app/child-dev-project/attendance/attendance-status-select/attendance-status-select.component.ts index 197643746d..097828aa9b 100644 --- a/src/app/child-dev-project/attendance/attendance-status-select/attendance-status-select.component.ts +++ b/src/app/child-dev-project/attendance/attendance-status-select/attendance-status-select.component.ts @@ -1,6 +1,9 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { ConfigService } from "../../../core/config/config.service"; -import { ConfigurableEnumConfig } from "../../../core/configurable-enum/configurable-enum.interface"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumConfig, +} from "../../../core/configurable-enum/configurable-enum.interface"; import { ATTENDANCE_STATUS_CONFIG_ID, AttendanceStatusType, @@ -21,6 +24,6 @@ export class AttendanceStatusSelectComponent { constructor(private configService: ConfigService) { this.statusValues = this.configService.getConfig< ConfigurableEnumConfig - >(ATTENDANCE_STATUS_CONFIG_ID); + >(CONFIGURABLE_ENUM_CONFIG_PREFIX + ATTENDANCE_STATUS_CONFIG_ID); } } diff --git a/src/app/child-dev-project/attendance/attendance.service.ts b/src/app/child-dev-project/attendance/attendance.service.ts index ec7c585491..b5903a8b01 100644 --- a/src/app/child-dev-project/attendance/attendance.service.ts +++ b/src/app/child-dev-project/attendance/attendance.service.ts @@ -12,6 +12,7 @@ import { } from "../notes/model/interaction-type.interface"; import { EventNote } from "./model/event-note"; import { ChildrenService } from "../children/children.service"; +import { CONFIGURABLE_ENUM_CONFIG_PREFIX } from "../../core/configurable-enum/configurable-enum.interface"; @Injectable({ providedIn: "root", @@ -28,7 +29,9 @@ export class AttendanceService { private createIndices() { const meetingInteractionTypes = this.configService - .getConfig(INTERACTION_TYPE_CONFIG_ID) + .getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + INTERACTION_TYPE_CONFIG_ID + ) .filter((t) => t.isMeeting) .map((t) => t.id); this.createEventsIndex(meetingInteractionTypes); diff --git a/src/app/child-dev-project/attendance/model/attendance-status.ts b/src/app/child-dev-project/attendance/model/attendance-status.ts index 8b5a0c628e..4e714c3c95 100644 --- a/src/app/child-dev-project/attendance/model/attendance-status.ts +++ b/src/app/child-dev-project/attendance/model/attendance-status.ts @@ -1,7 +1,4 @@ -import { - CONFIGURABLE_ENUM_CONFIG_PREFIX, - ConfigurableEnumValue, -} from "../../../core/configurable-enum/configurable-enum.interface"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; /** * @deprecated @@ -27,8 +24,7 @@ export enum AttendanceLogicalStatus { /** * the id through which the available attendance status types can be loaded from the ConfigService. */ -export const ATTENDANCE_STATUS_CONFIG_ID = - CONFIGURABLE_ENUM_CONFIG_PREFIX + "attendance-status"; +export const ATTENDANCE_STATUS_CONFIG_ID = "attendance-status"; /** * Details of one status option users can assign to a participant's details attending an event. diff --git a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts index e441db7bd9..da6e309b8e 100644 --- a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts +++ b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts @@ -17,7 +17,10 @@ import { AttendanceStatusType, } from "../../attendance/model/attendance-status"; import { ConfigService } from "../../../core/config/config.service"; -import { ConfigurableEnumConfig } from "../../../core/configurable-enum/configurable-enum.interface"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumConfig, +} from "../../../core/configurable-enum/configurable-enum.interface"; import { DemoUserGeneratorService } from "../../../core/user/demo-user-generator.service"; export class DemoNoteConfig { @@ -62,7 +65,7 @@ export class DemoNoteGeneratorService extends DemoDataGenerator { this.availableStatusTypes = this.configService.getConfig< ConfigurableEnumConfig - >(ATTENDANCE_STATUS_CONFIG_ID); + >(CONFIGURABLE_ENUM_CONFIG_PREFIX + ATTENDANCE_STATUS_CONFIG_ID); } public generateEntities(): Note[] { diff --git a/src/app/child-dev-project/notes/model/interaction-type.interface.ts b/src/app/child-dev-project/notes/model/interaction-type.interface.ts index f38ad265e7..e606e00252 100644 --- a/src/app/child-dev-project/notes/model/interaction-type.interface.ts +++ b/src/app/child-dev-project/notes/model/interaction-type.interface.ts @@ -1,7 +1,4 @@ -import { - CONFIGURABLE_ENUM_CONFIG_PREFIX, - ConfigurableEnumValue, -} from "../../../core/configurable-enum/configurable-enum.interface"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; /** * Additional properties defined in the "interaction-type" {@link ConfigurableEnumValue} values @@ -18,5 +15,4 @@ export interface InteractionType extends ConfigurableEnumValue { /** * ID of the Note category {@link ConfigurableEnumValue} in the config database. */ -export const INTERACTION_TYPE_CONFIG_ID = - CONFIGURABLE_ENUM_CONFIG_PREFIX + "interaction-type"; +export const INTERACTION_TYPE_CONFIG_ID = "interaction-type"; diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index 925bf5c0a4..4a5b283a0f 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -77,7 +77,9 @@ describe("Note", () => { testConfigs[ CONFIGURABLE_ENUM_CONFIG_PREFIX + INTERACTION_TYPE_CONFIG_ID ] = testInteractionTypes; - testConfigs[ATTENDANCE_STATUS_CONFIG_ID] = testStatusTypes; + testConfigs[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + ATTENDANCE_STATUS_CONFIG_ID + ] = testStatusTypes; entitySchemaService = new EntitySchemaService(); entitySchemaService.registerSchemaDatatype( diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index e9ef055561..334db356fa 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -247,9 +247,6 @@ export const defaultJsonConfig = { }, { "id": "category", - "label": "Category", - "type": "configurable-enum", - "enumId": "interaction-type", "display": "dropdown" } ] @@ -294,7 +291,6 @@ export const defaultJsonConfig = { }, { "id": "privateSchool", - "type": "boolean", "default": "", "true": "Private School", "false": "Government School", @@ -484,14 +480,11 @@ export const defaultJsonConfig = { }, { "id": "center", - "label": "Center", - "type": "configurable-enum", - "enumId": "center", "display": "dropdown" }, { - "id": "school", - "type": "prebuilt", + "id": "schoolId", + "type": "School", "label": "School", "display": "dropdown" } diff --git a/src/app/core/entity-components/entity-details/entity-details.component.ts b/src/app/core/entity-components/entity-details/entity-details.component.ts index d1ada07d72..dc63b356b0 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.ts @@ -21,7 +21,7 @@ import { } from "../../permissions/entity-permissions.service"; import { User } from "../../user/user"; -export const ENTITY_MAP: Map> = new Map< +export const ENTITY_MAP: Map> = new Map< string, EntityConstructor >([ diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts index ce4defd26d..0ebba18554 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts @@ -26,7 +26,7 @@ export class EditSingleEntityComponent extends EditComponent { .then((entities) => entities.sort((e1, e2) => { if (e1.hasOwnProperty("name")) { - return e1.name.localeCompare(e2.name); + return e1["name"].localeCompare(e2["name"]); } else { return 0; } diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index dc5941401f..77deee85de 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -11,36 +11,19 @@ import { import { MediaChange, MediaObserver } from "@angular/flex-layout"; import { ActivatedRoute, Router } from "@angular/router"; import { - BooleanFilterConfig, ColumnGroupsConfig, - ConfigurableEnumFilterConfig, EntityListConfig, FilterConfig, GroupConfig, - PrebuiltFilterConfig, } from "./EntityListConfig"; import { Entity, EntityConstructor } from "../../entity/entity"; -import { - FilterSelection, - FilterSelectionOption, -} from "../../filter/filter-selection/filter-selection"; -import { SessionService } from "../../session/session-service/session.service"; -import { ConfigService } from "../../config/config.service"; -import { - CONFIGURABLE_ENUM_CONFIG_PREFIX, - ConfigurableEnumConfig, -} from "../../configurable-enum/configurable-enum.interface"; -import { LoggingService } from "../../logging/logging.service"; import { OperationType } from "../../permissions/entity-permissions.service"; import { FormFieldConfig } from "../entity-details/form/FormConfig"; import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; - -interface FilterComponentSettings { - filterSettings: FilterSelection; - selectedOption?: string; - display?: string; - label?: string; -} +import { + FilterComponentSettings, + FilterGeneratorService, +} from "./filter-generator.service"; /** * This component allows to create a full blown table with pagination, filtering, searching and grouping. @@ -83,12 +66,10 @@ export class EntityListComponent filterString = ""; constructor( - private configService: ConfigService, - private loggingService: LoggingService, - private sessionService: SessionService, private media: MediaObserver, private router: Router, - private activatedRoute: ActivatedRoute + private activatedRoute: ActivatedRoute, + private filterGeneratorService: FilterGeneratorService ) {} ngOnInit() { @@ -210,87 +191,12 @@ export class EntityListComponent }); } - private initFilterSelections() { - const filterSelections = []; - - for (const filter of this.filtersConfig) { - const fs: FilterComponentSettings = { - filterSettings: new FilterSelection(filter.id, [], filter.label), - display: filter.display, - }; - fs.filterSettings.options = this.initFilterOptions(filter); - - // Filters should only be added, if they have more than one (the default) option - if (fs.filterSettings.options?.length > 1) { - fs.selectedOption = filter.hasOwnProperty("default") - ? filter.default - : fs.filterSettings.options[0].key; - filterSelections.push(fs); - } - } - - this.filterSelections = filterSelections; - } - - private initFilterOptions(config: FilterConfig): FilterSelectionOption[] { - switch (config.type) { - case "boolean": - return this.createBooleanFilterOptions(config as BooleanFilterConfig); - case "prebuilt": - return (config as PrebuiltFilterConfig).options; - case "configurable-enum": - return this.createConfigurableEnumFilterOptions( - config as ConfigurableEnumFilterConfig - ); - default: { - const options = [...new Set(this.allEntities.map((c) => c[config.id]))]; - return FilterSelection.generateOptions(options, config.id); - } - } - } - - private createBooleanFilterOptions( - filter: BooleanFilterConfig - ): FilterSelectionOption[] { - return [ - { key: "", label: filter.all, filterFun: () => true }, - { - key: "true", - label: filter.true, - filterFun: (c: Entity) => c[filter.id], - }, - { - key: "false", - label: filter.false, - filterFun: (c: Entity) => !c[filter.id], - }, - ]; - } - - private createConfigurableEnumFilterOptions( - config: ConfigurableEnumFilterConfig - ) { - const options = [{ key: "*", label: "All", filterFun: (e: T) => true }]; - - const enumValues = this.configService.getConfig( - CONFIGURABLE_ENUM_CONFIG_PREFIX + config.enumId + private async initFilterSelections(): Promise { + this.filterSelections = await this.filterGeneratorService.generate( + this.filtersConfig, + this.entityConstructor, + this.allEntities ); - if (!enumValues) { - this.loggingService.warn( - "Could not load enum options for filter from config: " + config.id - ); - return options; - } - - for (const enumValue of enumValues) { - options.push({ - key: enumValue.id, - label: enumValue.label, - filterFun: (entity) => entity[config.id]?.id === enumValue.id, - }); - } - - return options; } private displayColumnGroup(columnGroupName: string) { From b14a90486fc8f8ebfb9b3bcf96dba066d3ea7aec Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 09:37:15 +0200 Subject: [PATCH 106/230] added service to generate filters --- .../form/form.component.spec.ts | 6 +- .../filter-generator.service.spec.ts | 29 ++++ .../entity-list/filter-generator.service.ts | 160 ++++++++++++++++++ .../entity-subrecord.component.ts | 2 +- 4 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 src/app/core/entity-components/entity-list/filter-generator.service.spec.ts create mode 100644 src/app/core/entity-components/entity-list/filter-generator.service.ts diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index c355d3409c..054ff558d8 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -128,7 +128,7 @@ describe("FormComponent", () => { [ { id: "fieldWithDefinition", - input: "InputComponent", + edit: "EditComponent", view: "DisplayComponent", placeholder: "Field with definition", }, @@ -142,13 +142,13 @@ describe("FormComponent", () => { [ { id: "fieldWithDefinition", - input: "InputComponent", + edit: "EditComponent", view: "DisplayComponent", placeholder: "Field with definition", }, { id: "propertyField", - input: "PredefinedComponent", + edit: "PredefinedComponent", view: "PredefinedComponent", placeholder: "Property", }, diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts new file mode 100644 index 0000000000..737104c422 --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts @@ -0,0 +1,29 @@ +import { TestBed } from "@angular/core/testing"; + +import { FilterGeneratorService } from "./filter-generator.service"; +import { ConfigService } from "../../config/config.service"; +import { EntityMapperService } from "../../entity/entity-mapper.service"; +import { LoggingService } from "../../logging/logging.service"; + +describe("FilterGeneratorService", () => { + let service: FilterGeneratorService; + let mockConfigService: jasmine.SpyObj; + let mockEntityMapper: jasmine.SpyObj; + + beforeEach(() => { + mockConfigService = jasmine.createSpyObj(["getConfig"]); + mockEntityMapper = jasmine.createSpyObj(["loadType"]); + TestBed.configureTestingModule({ + providers: [ + { provide: ConfigService, useValue: mockConfigService }, + { provide: EntityMapperService, useValue: EntityMapperService }, + LoggingService, + ], + }); + service = TestBed.inject(FilterGeneratorService); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts new file mode 100644 index 0000000000..81e671b573 --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -0,0 +1,160 @@ +import { Injectable } from "@angular/core"; +import { + FilterSelection, + FilterSelectionOption, +} from "../../filter/filter-selection/filter-selection"; +import { + BooleanFilterConfig, + FilterConfig, + PrebuiltFilterConfig, +} from "./EntityListConfig"; +import { ENTITY_MAP } from "../entity-details/entity-details.component"; +import { Entity, EntityConstructor } from "../../entity/entity"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumConfig, +} from "../../configurable-enum/configurable-enum.interface"; +import { ConfigService } from "../../config/config.service"; +import { LoggingService } from "../../logging/logging.service"; +import { EntityMapperService } from "../../entity/entity-mapper.service"; +import { EntitySchemaField } from "../../entity/schema/entity-schema-field"; + +export interface FilterComponentSettings { + filterSettings: FilterSelection; + selectedOption?: string; + display?: string; + label?: string; +} + +@Injectable({ + providedIn: "root", +}) +export class FilterGeneratorService { + constructor( + private configService: ConfigService, + private loggingService: LoggingService, + private entityMapperService: EntityMapperService + ) {} + + async generate( + filtersConfig: FilterConfig[], + entityConstructor: EntityConstructor, + data: T[] + ): Promise[]> { + const filterSettings: FilterComponentSettings[] = []; + for (const filter of filtersConfig) { + const schema = entityConstructor.schema.get(filter.id) || {}; + const fs: FilterComponentSettings = { + filterSettings: new FilterSelection( + filter.id, + [], + filter.label || schema.label + ), + display: filter.display, + }; + try { + fs.filterSettings.options = await this.getFilterOptions( + filter, + schema, + data + ); + } catch (e) { + this.loggingService.warn(`Could not init filter: ${filter.id}: ${e}`); + } + + // Filters should only be added, if they have more than one (the default) option + if (fs.filterSettings.options?.length > 1) { + fs.selectedOption = filter.hasOwnProperty("default") + ? filter.default + : fs.filterSettings.options[0].key; + filterSettings.push(fs); + } + } + return filterSettings; + } + private async getFilterOptions( + config: FilterConfig, + schema: EntitySchemaField, + data: T[] + ): Promise[]> { + if (schema.dataType === "boolean" || config.type === "boolean") { + return this.createBooleanFilterOptions(config as BooleanFilterConfig); + } else if (schema.dataType === "configurable-enum") { + return this.createConfigurableEnumFilterOptions( + config.id, + schema.innerDataType + ); + } else if (ENTITY_MAP.has(config.type) || ENTITY_MAP.has(schema.ext)) { + return await this.createEntityFilterOption( + config.id, + config.type || schema.ext + ); + } else if (config.type === "prebuilt") { + return (config as PrebuiltFilterConfig).options; + } else { + const options = [...new Set(data.map((c) => c[config.id]))]; + return FilterSelection.generateOptions(options, config.id); + } + } + + private createBooleanFilterOptions( + filter: BooleanFilterConfig + ): FilterSelectionOption[] { + return [ + { key: "", label: filter.all, filterFun: () => true }, + { + key: "true", + label: filter.true, + filterFun: (c: Entity) => c[filter.id], + }, + { + key: "false", + label: filter.false, + filterFun: (c: Entity) => !c[filter.id], + }, + ]; + } + + private createConfigurableEnumFilterOptions( + property: string, + enumId: string + ): FilterSelectionOption[] { + const options = [{ key: "*", label: "All", filterFun: (e: T) => true }]; + + const enumValues = this.configService.getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId + ); + + for (const enumValue of enumValues) { + options.push({ + key: enumValue.id, + label: enumValue.label, + filterFun: (entity) => entity[property]?.id === enumValue.id, + }); + } + + return options; + } + + private async createEntityFilterOption( + property: string, + entityType: string + ): Promise[]> { + const entityConstructor = ENTITY_MAP.get(entityType); + const filterEntities = await this.entityMapperService.loadType( + entityConstructor + ); + + const options = [{ key: "*", label: "All", filterFun: (e: T) => true }]; + options.push( + ...filterEntities.map((filterEntity) => { + return { + key: filterEntity.getId(), + label: filterEntity["name"] || filterEntity.getId(), + filterFun: (entity) => entity[property] === filterEntity.getId(), + }; + }) + ); + return options; + } +} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index c7380e697d..cdc8356b19 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -166,7 +166,7 @@ export class EntitySubrecordComponent let sortDirection = "asc"; if ( sortByColumn?.view === "DisplayDate" || - sortByColumn.edit === "EditDate" + sortByColumn?.edit === "EditDate" ) { // flip default sort order for dates (latest first) sortDirection = "desc"; From 2678eaeb23900b67dc2862d16696d0c113ab39ec Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 10:33:48 +0200 Subject: [PATCH 107/230] added tests for filter service --- .../filter-generator.service.spec.ts | 171 +++++++++++++++++- .../entity-list/filter-generator.service.ts | 10 +- 2 files changed, 175 insertions(+), 6 deletions(-) diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts index 737104c422..101dd9c4ec 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts @@ -4,6 +4,13 @@ import { FilterGeneratorService } from "./filter-generator.service"; import { ConfigService } from "../../config/config.service"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { LoggingService } from "../../logging/logging.service"; +import { BooleanFilterConfig, PrebuiltFilterConfig } from "./EntityListConfig"; +import { School } from "../../../child-dev-project/schools/model/school"; +import { Note } from "../../../child-dev-project/notes/model/note"; +import { defaultInteractionTypes } from "../../config/default-config/default-interaction-types"; +import { ChildSchoolRelation } from "../../../child-dev-project/children/model/childSchoolRelation"; +import { Child } from "../../../child-dev-project/children/model/child"; +import moment from "moment"; describe("FilterGeneratorService", () => { let service: FilterGeneratorService; @@ -16,7 +23,7 @@ describe("FilterGeneratorService", () => { TestBed.configureTestingModule({ providers: [ { provide: ConfigService, useValue: mockConfigService }, - { provide: EntityMapperService, useValue: EntityMapperService }, + { provide: EntityMapperService, useValue: mockEntityMapper }, LoggingService, ], }); @@ -26,4 +33,166 @@ describe("FilterGeneratorService", () => { it("should be created", () => { expect(service).toBeTruthy(); }); + + it("should create a boolean filter", async () => { + const filterConfig: BooleanFilterConfig = { + id: "privateSchool", + true: "Private", + false: "Government", + all: "All", + }; + const schema = School.schema.get("privateSchool"); + + const filter = (await service.generate([filterConfig], School, []))[0]; + + expect(filter.filterSettings.label).toEqual(schema.label); + expect(filter.filterSettings.name).toEqual("privateSchool"); + expect( + filter.filterSettings.options.map((option) => { + return { key: option.key, label: option.label }; + }) + ).toEqual([ + { key: "", label: "All" }, + { key: "true", label: "Private" }, + { key: "false", label: "Government" }, + ]); + }); + + it("should create a configurable enum filter", async () => { + mockConfigService.getConfig.and.returnValue(defaultInteractionTypes); + const interactionTypes = defaultInteractionTypes.map((it) => { + return { key: it.id, label: it.label }; + }); + interactionTypes.push({ key: "", label: "All" }); + const schema = Note.schema.get("category"); + + const filter = (await service.generate([{ id: "category" }], Note, []))[0]; + + expect(filter.filterSettings.label).toEqual(schema.label); + expect(filter.filterSettings.name).toEqual("category"); + const comparableOptions = filter.filterSettings.options.map((option) => { + return { key: option.key, label: option.label }; + }); + expect(comparableOptions).toEqual( + jasmine.arrayWithExactContents(interactionTypes) + ); + }); + + it("should create a entity filter", async () => { + const school1 = new School(); + school1.name = "First School"; + const school2 = new School(); + school2.name = "Second School"; + mockEntityMapper.loadType.and.resolveTo([school1, school2]); + const csr1 = new ChildSchoolRelation(); + csr1.schoolId = school1.getId(); + const csr2 = new ChildSchoolRelation(); + csr2.schoolId = school2.getId(); + const csr3 = new ChildSchoolRelation(); + csr3.schoolId = school2.getId(); + const csr4 = new ChildSchoolRelation(); + csr4.schoolId = school1.getId(); + const schema = ChildSchoolRelation.schema.get("schoolId"); + + const filter = ( + await service.generate([{ id: "schoolId" }], ChildSchoolRelation, []) + )[0]; + + expect(filter.filterSettings.label).toEqual(schema.label); + expect(filter.filterSettings.name).toEqual("schoolId"); + const allRelations = [csr1, csr2, csr3, csr4]; + const allFilter = filter.filterSettings.options.find( + (opt) => opt.key === "" + ); + expect(allFilter.label).toEqual("All"); + expect(allRelations.filter(allFilter.filterFun)).toEqual(allRelations); + const school1Filter = filter.filterSettings.options.find( + (opt) => opt.key === school1.getId() + ); + expect(school1Filter.label).toEqual(school1.name); + expect(allRelations.filter(school1Filter.filterFun)).toEqual([csr1, csr4]); + const school2Filter = filter.filterSettings.options.find( + (opt) => opt.key === school2.getId() + ); + expect(school2Filter.label).toEqual(school2.name); + expect(allRelations.filter(school2Filter.filterFun)).toEqual([csr2, csr3]); + }); + + it("should create filters with all possible options on default", async () => { + const child1 = new Child(); + child1.religion = "muslim"; + const child2 = new Child(); + child2.religion = "christian"; + const child3 = new Child(); + child3.religion = "muslim"; + const schema = Child.schema.get("religion"); + + const filter = ( + await service.generate([{ id: "religion" }], Child, [ + child1, + child2, + child3, + ]) + )[0]; + + expect(filter.filterSettings.label).toEqual(schema.label); + expect(filter.filterSettings.name).toEqual("religion"); + const comparableOptions = filter.filterSettings.options.map((option) => { + return { key: option.key, label: option.label }; + }); + expect(comparableOptions).toEqual( + jasmine.arrayWithExactContents([ + { key: "", label: "All" }, + { key: "muslim", label: "muslim" }, + { key: "christian", label: "christian" }, + ]) + ); + }); + + it("should use values from a prebuilt filter", async () => { + const prebuiltFilter: PrebuiltFilterConfig = { + id: "date", + type: "prebuilt", + label: "Date", + default: "today", + options: [ + { key: "", label: "All", filterFun: () => true }, + { + key: "today", + label: "Today", + filterFun: (note) => moment().isSame(note.date, "day"), + }, + { + key: "before", + label: "Before today", + filterFun: (note) => moment().isAfter(note.date, "day"), + }, + ], + }; + + const filter = (await service.generate([prebuiltFilter], Note, []))[0]; + + expect(filter.filterSettings.label).toEqual(prebuiltFilter.label); + expect(filter.filterSettings.name).toEqual(prebuiltFilter.id); + expect(filter.filterSettings.options).toEqual(prebuiltFilter.options); + expect(filter.selectedOption).toEqual(prebuiltFilter.default); + + const todayNote = new Note(); + todayNote.date = new Date(); + const yesterdayNote = new Note(); + const notes = [todayNote, yesterdayNote]; + yesterdayNote.date = moment().subtract(1, "day").toDate(); + const allFilter = filter.filterSettings.options.find( + (filter) => filter.key === "" + ); + expect(notes.filter(allFilter.filterFun)).toEqual(notes); + const todayFilter = filter.filterSettings.options.find( + (filter) => filter.key === "today" + ); + expect(notes.filter(todayFilter.filterFun)).toEqual([todayNote]); + const beforeFilter = filter.filterSettings.options.find( + (filter) => filter.key === "before" + ); + expect(notes.filter(beforeFilter.filterFun)).toEqual([yesterdayNote]); + }); }); diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index 81e671b573..339f2d3f06 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -77,7 +77,9 @@ export class FilterGeneratorService { schema: EntitySchemaField, data: T[] ): Promise[]> { - if (schema.dataType === "boolean" || config.type === "boolean") { + if (config.type === "prebuilt") { + return (config as PrebuiltFilterConfig).options; + } else if (schema.dataType === "boolean" || config.type === "boolean") { return this.createBooleanFilterOptions(config as BooleanFilterConfig); } else if (schema.dataType === "configurable-enum") { return this.createConfigurableEnumFilterOptions( @@ -89,8 +91,6 @@ export class FilterGeneratorService { config.id, config.type || schema.ext ); - } else if (config.type === "prebuilt") { - return (config as PrebuiltFilterConfig).options; } else { const options = [...new Set(data.map((c) => c[config.id]))]; return FilterSelection.generateOptions(options, config.id); @@ -119,7 +119,7 @@ export class FilterGeneratorService { property: string, enumId: string ): FilterSelectionOption[] { - const options = [{ key: "*", label: "All", filterFun: (e: T) => true }]; + const options = [{ key: "", label: "All", filterFun: (e: T) => true }]; const enumValues = this.configService.getConfig( CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId @@ -145,7 +145,7 @@ export class FilterGeneratorService { entityConstructor ); - const options = [{ key: "*", label: "All", filterFun: (e: T) => true }]; + const options = [{ key: "", label: "All", filterFun: (e: T) => true }]; options.push( ...filterEntities.map((filterEntity) => { return { From 0e63a21b8f6598c4998461b6d41f154d3c1f16da Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 10:38:20 +0200 Subject: [PATCH 108/230] removed duplicate tests --- .../entity-list/entity-list.component.spec.ts | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 449c3d6b86..4dafc190bb 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -1,6 +1,5 @@ import { ComponentFixture, - fakeAsync, TestBed, waitForAsync, } from "@angular/core/testing"; @@ -9,7 +8,6 @@ import { CommonModule, DatePipe } from "@angular/common"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { RouterTestingModule } from "@angular/router/testing"; import { SimpleChange } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; import { BooleanFilterConfig, EntityListConfig } from "./EntityListConfig"; import { Entity } from "../../entity/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; @@ -186,62 +184,6 @@ describe("EntityListComponent", () => { }); }); - it("should navigate to the correct url params when clicking a filter", () => { - const router = TestBed.inject(Router); - spyOn(router, "navigate"); - const dropoutFs = component.filterSelections[0]; - const clickedOption = (testConfig.filters[0] as BooleanFilterConfig).false; - const route = TestBed.inject(ActivatedRoute); - - component.filterOptionSelected(dropoutFs, clickedOption); - - const expectedParams = {}; - expectedParams[dropoutFs.filterSettings.name] = clickedOption; - expect(router.navigate).toHaveBeenCalledWith([], { - relativeTo: route, - queryParams: expectedParams, - queryParamsHandling: "merge", - }); - }); - - it("correctly create dropdown and selection filters if values are present", fakeAsync(() => { - const child = new Child(); - child.religion = "muslim"; - component.allEntities = [child]; - component.ngOnChanges({ allEntities: null }); - expect(component.filterSelections.length).toEqual(2); - expect( - component.filterSelections - .filter((e) => e.display !== "dropdown") - .map((e) => e.filterSettings.name) - ).toEqual(["isActive"]); - expect( - component.filterSelections - .filter((e) => e.display === "dropdown") - .map((e) => e.filterSettings.name) - ).toEqual(["religion"]); - })); - - it("should create default column groups and filters", () => { - component.listConfig = { - title: testConfig.title, - columns: testConfig.columns, - }; - component.ngOnChanges({ - listConfig: new SimpleChange(false, component.listConfig, false), - allEntities: new SimpleChange(false, component.allEntities, false), - }); - expect(component.columnGroups).toEqual([ - { name: "default", columns: testConfig.columns.map((c) => c.id) }, - ]); - expect(component.defaultColumnGroup).toEqual( - component.columnGroups[0].name - ); - expect(component.mobileColumnGroup).toEqual(component.columnGroups[0].name); - expect(component.filtersConfig).toEqual([]); - expect(component.filterSelections).toEqual([]); - }); - it("should add and initialize columns which are only mentioned in the columnGroups", () => { class Test extends Entity { @DatabaseField({ label: "Test Property" }) testProperty: string; From fc2611f42a3b5d78c8eb74f7775eeb39710e6899 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 12:00:02 +0200 Subject: [PATCH 109/230] increased test coverage for entity subrecord component --- .../entity-subrecord.component.spec.ts | 138 +++++++++++++++++- .../entity-subrecord.component.ts | 4 +- .../keys-pipe/keys.pipe.spec.ts | 11 ++ .../entity-subrecord/keys-pipe/keys.pipe.ts | 4 +- 4 files changed, 151 insertions(+), 6 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 966ed302f3..6f779378c6 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -1,6 +1,15 @@ -import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; +import { + ComponentFixture, + fakeAsync, + TestBed, + tick, + waitForAsync, +} from "@angular/core/testing"; -import { EntitySubrecordComponent } from "./entity-subrecord.component"; +import { + EntitySubrecordComponent, + TableRow, +} from "./entity-subrecord.component"; import { RouterTestingModule } from "@angular/router/testing"; import { EntitySubrecordModule } from "../entity-subrecord.module"; import { Entity } from "../../../entity/entity"; @@ -13,6 +22,13 @@ import { ConfigurableEnumValue } from "../../../configurable-enum/configurable-e import { Child } from "../../../../child-dev-project/children/model/child"; import { Note } from "../../../../child-dev-project/notes/model/note"; import { AlertService } from "../../../alerts/alert.service"; +import { PageEvent } from "@angular/material/paginator"; +import { FormBuilder, FormGroup } from "@angular/forms"; +import { Gender } from "../../../../child-dev-project/children/model/Gender"; +import { EntityFormService } from "../../entity-form/entity-form.service"; +import { Subject } from "rxjs"; +import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; +import { MatSnackBar } from "@angular/material/snack-bar"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -209,4 +225,122 @@ describe("EntitySubrecordComponent", () => { expect(alertService.addWarning).toHaveBeenCalled(); }); + + it("should trigger an update of the paginator when changing the page size", fakeAsync(() => { + component.ngOnChanges({ records: null }); + + component.onPaginateChange({ pageSize: 20 } as PageEvent); + tick(); + + expect(component.paginator.pageSize).toEqual(20); + })); + + it("should create a formGroup when editing a row", () => { + component.columns = [{ id: "name" }, { id: "projectNumber" }]; + const child = new Child(); + child.name = "Child Name"; + child.projectNumber = "01"; + const tableRow: TableRow = { record: child }; + + component.edit(tableRow); + + const formGroup = tableRow.formGroup; + expect(formGroup.get("name").value).toBe("Child Name"); + expect(formGroup.get("projectNumber").value).toBe("01"); + expect(formGroup.enabled).toBeTrue(); + }); + + it("should correctly save changes to a entity", fakeAsync(() => { + mockEntityMapper.save.and.resolveTo(); + const fb = TestBed.inject(FormBuilder); + const child = new Child(); + child.name = "Old Name"; + const formGroup = fb.group({ + name: "New Name", + gender: Gender.FEMALE, + }); + + component.save({ record: child, formGroup: formGroup }); + tick(); + + expect(mockEntityMapper.save).toHaveBeenCalledWith(child); + expect(child.name).toBe("New Name"); + expect(child.gender).toBe(Gender.FEMALE); + expect(formGroup.disabled).toBeTrue(); + })); + + it("should show a error message when saving fails", fakeAsync(() => { + const entityFormService = TestBed.inject(EntityFormService); + spyOn(entityFormService, "saveChanges").and.rejectWith( + new Error("Form invalid") + ); + const alertService = TestBed.inject(AlertService); + spyOn(alertService, "addDanger"); + + component.save({ formGroup: null, record: null }); + tick(); + + expect(alertService.addDanger).toHaveBeenCalledWith("Form invalid"); + })); + + it("should clear the form group when resetting", () => { + const row = { record: new Child(), formGroup: new FormGroup({}) }; + + component.resetChanges(row); + + expect(row.formGroup).toBeFalsy(); + }); + + it("should save a deleted entity when clicking the popup", fakeAsync(() => { + const dialogService = TestBed.inject(ConfirmationDialogService); + const dialogObservable = new Subject(); + spyOn(dialogService, "openDialog").and.returnValue({ + afterClosed: () => dialogObservable, + } as any); + const snackbarService = TestBed.inject(MatSnackBar); + const snackbarObservable = new Subject(); + spyOn(snackbarService, "open").and.returnValue({ + onAction: () => snackbarObservable, + } as any); + mockEntityMapper.remove.and.resolveTo(); + const child = new Child(); + component.records = [child]; + + component.delete({ record: child }); + tick(); + expect(component.records).toEqual([child]); + + dialogObservable.next(true); + tick(); + expect(mockEntityMapper.remove).toHaveBeenCalledWith(child); + expect(component.records).toEqual([]); + + snackbarObservable.next(); + expect(mockEntityMapper.save).toHaveBeenCalledWith(child, true); + expect(component.records).toEqual([child]); + })); + + it("should create new entities and make them editable", fakeAsync(() => { + const child = new Child(); + component.newRecordFactory = () => child; + component.columns = [{ id: "name" }, { id: "projectNumber" }]; + + component.create(); + + expect(component.records).toEqual([child]); + const tableRow = component.recordsDataSource.data.find( + (row) => row.record === child + ); + expect(tableRow.formGroup.enabled).toBeTrue(); + })); + + it("should notify when an entity is clicked", (done) => { + const child = new Child(); + component.rowClicked.subscribe((entity) => { + expect(entity).toEqual(child); + done(); + }); + + component.showRecord({ record: child }); + }); }); diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index cdc8356b19..47321d1057 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -25,7 +25,7 @@ import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-details/form/FormConfig"; import { EntityFormService } from "../../entity-form/entity-form.service"; -interface TableRow { +export interface TableRow { record: T; formGroup?: FormGroup; } @@ -343,7 +343,7 @@ export class EntitySubrecordComponent * @param col column that is checked * @return returns true if column is visible */ - isVisible(col) { + private isVisible(col) { let returnVal; switch (col.visibleFrom) { case "xl": { diff --git a/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.spec.ts b/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.spec.ts index 4237eeca87..6cc930e4ec 100644 --- a/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.spec.ts @@ -5,4 +5,15 @@ describe("KeysPipe", () => { const pipe = new KeysPipe(); expect(pipe).toBeTruthy(); }); + + it("should create key value pairs of an object", () => { + const obj = { first: "First", second: "Second" }; + + const res = new KeysPipe().transform(obj); + + expect(res).toEqual([ + { key: "first", value: "First" }, + { key: "second", value: "Second" }, + ]); + }); }); diff --git a/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.ts b/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.ts index 4262cb7e4a..9542050915 100644 --- a/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.ts +++ b/src/app/core/entity-components/entity-subrecord/keys-pipe/keys.pipe.ts @@ -12,8 +12,8 @@ import { Pipe, PipeTransform } from "@angular/core"; export class KeysPipe implements PipeTransform { transform(value: any, args?: any): any { const keys = []; - for (const enumMember of Object.keys(value)) { - keys.push({ key: enumMember, value: value[enumMember] }); + for (const key of Object.keys(value)) { + keys.push({ key: key, value: value[key] }); } return keys; } From a12b2b04857bc92403a87f4770b6b2120a549ce8 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 25 May 2021 20:13:19 +0200 Subject: [PATCH 110/230] added tests to entity list and edit single entity components --- .../edit-single-entity.component.spec.ts | 29 +++++++++++++++---- .../entity-list/entity-list.component.spec.ts | 8 +++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts index d0cac61882..01017eaa48 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing"; import { EditSingleEntityComponent } from "./edit-single-entity.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; @@ -6,8 +6,9 @@ import { EntityFormModule } from "../../entity-form.module"; import { FormControl } from "@angular/forms"; import { EntitySchemaService } from "../../../../entity/schema/entity-schema.service"; import { EntityFormService } from "../../entity-form.service"; -import { Child } from "../../../../../child-dev-project/children/model/child"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { ChildSchoolRelation } from "../../../../../child-dev-project/children/model/childSchoolRelation"; +import { School } from "../../../../../child-dev-project/schools/model/school"; describe("EditSingleEntityComponent", () => { let component: EditSingleEntityComponent; @@ -33,13 +34,31 @@ describe("EditSingleEntityComponent", () => { component = fixture.componentInstance; const entityFormService = TestBed.inject(EntityFormService); component.formControl = entityFormService - .createFormGroup([{ id: "name" }], new Child()) - .get("name") as FormControl; - component.formControlName = "name"; + .createFormGroup([{ id: "schoolId" }], new ChildSchoolRelation()) + .get("schoolId") as FormControl; + component.formControlName = "schoolId"; fixture.detectChanges(); }); it("should create", () => { expect(component).toBeTruthy(); }); + + it("should show all entities of the given type", fakeAsync(() => { + const school1 = new School(); + school1.name = "First School"; + const school2 = new School(); + school2.name = "Second School"; + mockEntityMapper.loadType.and.resolveTo([school1, school2]); + + component.onInitFromDynamicConfig({ + formFieldConfig: { id: "schoolId" }, + formControl: component.formControl, + propertySchema: ChildSchoolRelation.schema.get("schoolId"), + }); + tick(); + + expect(mockEntityMapper.loadType).toHaveBeenCalled(); + expect(component.entities).toEqual([school1, school2]); + })); }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 4dafc190bb..05670e91ef 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -213,4 +213,12 @@ describe("EntityListComponent", () => { jasmine.arrayWithExactContents(["testProperty", "anotherColumn"]) ); }); + + it("should create records of the correct entity", () => { + component.entityConstructor = Child; + + const res = component.getNewRecordFactory()(); + + expect(res.getType()).toEqual(Child.ENTITY_TYPE); + }); }); From 15100593ef0888d26151d66a78639b3f4f40b149 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 11:35:30 +0200 Subject: [PATCH 111/230] fixed sorting behavior --- .../entity-subrecord/entity-subrecord.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index f618ca6d67..a42d44e905 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -12,6 +12,7 @@ *matHeaderCellDef [matTooltip]="col.tooltip" [matTooltipDisabled]="!col.tooltip" + [disabled]="col.noSorting" > {{ col.placeholder }} From 64a0ade0da5450c587f67fbc0e6534f988e22c1f Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 11:53:29 +0200 Subject: [PATCH 112/230] cleaned up config --- src/app/core/config/config-fix.ts | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 334db356fa..c01e925297 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -691,23 +691,11 @@ export const defaultJsonConfig = { "component": "ActivityList", "config": { "title": "Recurring Activities", - "columns": [], - "columnGroups": { - "default": "All", - "mobile": "All", - "groups": [ - { - "name": "All", - "columns": [ - "title", - "type", - "assignedTo" - ] - } - ] - }, - "filters": [ - ] + "columns": [ + { "id": "title" }, + { "id": "type" }, + { "id": "assignedTo" } + ], } }, "view:recurring-activity/:id": { From c0cd9d18c3662fffb910a3dfc6be2fb03091c6a0 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 12:10:55 +0200 Subject: [PATCH 113/230] using entity subrecord in children overview --- .../children-overview.component.html | 23 ------ .../children-overview.component.ts | 70 +++++++------------ .../schools/schools.module.ts | 2 + 3 files changed, 27 insertions(+), 68 deletions(-) delete mode 100644 src/app/child-dev-project/schools/children-overview/children-overview.component.html diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.html b/src/app/child-dev-project/schools/children-overview/children-overview.component.html deleted file mode 100644 index e9b808d3a8..0000000000 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - {{ col.label }} - - - {{ student[col.name] }} - - - - - -
diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts index e0fff0fc90..c5169d23e3 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts @@ -1,65 +1,45 @@ -import { AfterViewInit, Component, ViewChild } from "@angular/core"; +import { Component } from "@angular/core"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { SchoolsService } from "../schools.service"; import { Child } from "../../children/model/child"; -import { MatTableDataSource } from "@angular/material/table"; -import { ColumnDescriptionInputType } from "../../../core/entity-components/entity-subrecord/column-description-input-type.enum"; -import { ColumnDescription } from "../../../core/entity-components/entity-subrecord/column-description"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { MatSort } from "@angular/material/sort"; +import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { Router } from "@angular/router"; /** * This component creates a table containing all children currently attending this school. */ @Component({ selector: "app-children-overview", - templateUrl: "./children-overview.component.html", + template: ``, }) -export class ChildrenOverviewComponent - implements OnInitDynamicComponent, AfterViewInit { - // This component can currently not use the EntitySubrecord, because EntitySubrecord does not allow to route to a - // different location but only open a popup when a record is clicked. - columns: ColumnDescription[] = [ - { - name: "projectNumber", - label: "PN", - inputType: ColumnDescriptionInputType.TEXT, - }, - { - name: "name", - label: "Name", - inputType: ColumnDescriptionInputType.TEXT, - }, - { - name: "schoolClass", - label: "Class", - inputType: ColumnDescriptionInputType.TEXT, - }, - { - name: "age", - label: "Age", - inputType: ColumnDescriptionInputType.TEXT, - }, +export class ChildrenOverviewComponent implements OnInitDynamicComponent { + columns: FormFieldConfig[] = [ + { id: "projectNumber" }, + { id: "name" }, + { id: "schoolClass", placeholder: "Class", view: "DisplayText" }, + { id: "age", placeholder: "Age", view: "DisplayText" }, ]; - displayedColumns = ["projectNumber", "name", "schoolClass", "age"]; + children: Child[] = []; - studentsDataSource: MatTableDataSource = new MatTableDataSource(); - @ViewChild(MatSort) sort: MatSort; + constructor(private schoolsService: SchoolsService, private router: Router) {} - constructor(private schoolsService: SchoolsService) {} - - ngAfterViewInit() { - this.studentsDataSource.sort = this.sort; - } - - onInitFromDynamicConfig(config: PanelConfig) { + async onInitFromDynamicConfig(config: PanelConfig) { if (config?.config?.displayedColumns) { - this.displayedColumns = config.config.displayedColumns; + this.columns = config.config.displayedColumns; } + this.children = await this.schoolsService.getChildrenForSchool( + config.entity.getId() + ); + } - this.schoolsService - .getChildrenForSchool(config.entity.getId()) - .then((children) => (this.studentsDataSource.data = children)); + routeToChild(child: Child) { + this.router.navigate([`/${child.getType().toLowerCase()}`, child.getId()]); } } diff --git a/src/app/child-dev-project/schools/schools.module.ts b/src/app/child-dev-project/schools/schools.module.ts index a06a52247c..d7746cea00 100644 --- a/src/app/child-dev-project/schools/schools.module.ts +++ b/src/app/child-dev-project/schools/schools.module.ts @@ -27,6 +27,7 @@ import { MatTooltipModule } from "@angular/material/tooltip"; import { Angulartics2Module } from "angulartics2"; import { ChildrenOverviewComponent } from "./children-overview/children-overview.component"; import { EntityListModule } from "../../core/entity-components/entity-list/entity-list.module"; +import { EntitySubrecordModule } from "../../core/entity-components/entity-subrecord/entity-subrecord.module"; @NgModule({ imports: [ @@ -68,6 +69,7 @@ import { EntityListModule } from "../../core/entity-components/entity-list/entit MatTooltipModule, Angulartics2Module, EntityListModule, + EntitySubrecordModule, ], declarations: [ SchoolBlockComponent, From 31986c758a69e72010358224d8660cf189c9939c Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 12:21:18 +0200 Subject: [PATCH 114/230] removed cyclic dependency to component map --- src/app/child-dev-project/children/model/child.ts | 4 ++++ src/app/child-dev-project/schools/model/school.ts | 4 ++++ .../display-entity/display-entity.component.ts | 10 ++++------ src/app/core/entity/entity.ts | 4 ++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 95f6efcc5c..26a5a5a676 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -37,6 +37,10 @@ export class Child extends Entity { return "assets/child.png"; } + static getBlockComponent(): string { + return "ChildBlock"; + } + /** * Returns the full relative filePath to a child photo given a filename, adding the relevant folders to it. * @param filename The given filename with file extension. diff --git a/src/app/child-dev-project/schools/model/school.ts b/src/app/child-dev-project/schools/model/school.ts index 3f4821ccc9..0a83e64961 100644 --- a/src/app/child-dev-project/schools/model/school.ts +++ b/src/app/child-dev-project/schools/model/school.ts @@ -4,6 +4,10 @@ import { DatabaseField } from "../../../core/entity/database-field.decorator"; @DatabaseEntity("School") export class School extends Entity { + static getBlockComponent(): string { + return "SchoolBlock"; + } + @DatabaseField({ label: "Name" }) name: string = ""; @DatabaseField({ label: "Address" }) address: string = ""; @DatabaseField({ label: "Medium" }) medium: string = ""; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 98634fe61d..ee70357a2b 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -1,6 +1,5 @@ import { Component, Input, OnInit } from "@angular/core"; import { Entity } from "../../../../entity/entity"; -import { DYNAMIC_COMPONENTS_MAP } from "../../../../view/dynamic-components-map"; import { OnInitDynamicComponent } from "../../../../view/dynamic-components/on-init-dynamic-component.interface"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; @@ -13,16 +12,15 @@ import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; }) export class DisplayEntityComponent implements OnInit, OnInitDynamicComponent { @Input() entity: Entity; - @Input() linkDisabled: boolean = false; + @Input() linkDisabled = false; entityBlockComponent: string; constructor(private entityMapper: EntityMapperService) {} ngOnInit(): void { if (this.entity) { - const blockComponentName = this.entity.getType() + "Block"; - if (DYNAMIC_COMPONENTS_MAP.has(blockComponentName)) { - this.entityBlockComponent = blockComponentName; - } + this.entityBlockComponent = this.entity + .getConstructor() + .getBlockComponent(); } } diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/entity.ts index 7478ba87c0..b2a4c990c5 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/entity.ts @@ -97,6 +97,10 @@ export class Entity { return; } + static getBlockComponent(): string { + return; + } + /** * Internal database id. * This is usually combined from the ENTITY_TYPE as a prefix with the entityId field `EntityType:entityId` From cb3a03e24e284933b0f8c74cf9c8b82148540ae0 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 12:40:58 +0200 Subject: [PATCH 115/230] fixed tests for children overview --- .../children-overview.component.spec.ts | 58 +++++++------------ 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts index 3d46104bc3..1b7a9e5ced 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts @@ -12,6 +12,8 @@ import { Child } from "../../children/model/child"; import { SchoolsService } from "../schools.service"; import { RouterTestingModule } from "@angular/router/testing"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { Router } from "@angular/router"; +import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; describe("ChildrenOverviewComponent", () => { let component: ChildrenOverviewComponent; @@ -26,7 +28,10 @@ describe("ChildrenOverviewComponent", () => { TestBed.configureTestingModule({ declarations: [], imports: [SchoolsModule, RouterTestingModule, NoopAnimationsModule], - providers: [{ provide: SchoolsService, useValue: schoolsService }], + providers: [ + { provide: SchoolsService, useValue: schoolsService }, + { provide: EntityMapperService, useValue: {} }, + ], }).compileComponents(); }) ); @@ -46,50 +51,27 @@ describe("ChildrenOverviewComponent", () => { const child1 = new Child("c1"); const child2 = new Child("c2"); const config = { entity: school }; - schoolsService.getChildrenForSchool.and.returnValue( - Promise.resolve([child1, child2]) - ); + schoolsService.getChildrenForSchool.and.resolveTo([child1, child2]); + component.onInitFromDynamicConfig(config); + expect(schoolsService.getChildrenForSchool).toHaveBeenCalledWith( school.getId() ); tick(); - expect(component.studentsDataSource.data).toEqual([child1, child2]); + expect(component.children).toEqual([child1, child2]); })); - function expectToBeSortedAccordingTo(specifier: string, sortedValues: any[]) { - let id = 0; - const ids = []; - // create an array of children with increasing id's - let children = sortedValues.map((value) => { - ids.push(id); - const child = new Child(String(id)); - id += 1; - child[specifier] = value; - return child; - }); - // shuffle the array - children = children - .map((a) => ({ sort: Math.random(), value: a })) - .sort((a, b) => a.sort - b.sort) - .map((a) => a.value); - // and re-sort it - component.sort.sort({ - id: specifier, - start: "asc", - disableClear: false, - }); - const sortedChildIds = component.studentsDataSource - .sortData(children, component.sort) - .map((it) => Number(it.getId())); - expect(sortedChildIds).toEqual(ids); - } + it("should route to a child when clicked", () => { + const router = TestBed.inject(Router); + spyOn(router, "navigate"); + const child = new Child(); + + component.routeToChild(child); - it("should sort the table according to the different column values", () => { - component.ngAfterViewInit(); - expectToBeSortedAccordingTo("name", ["AA", "AB", "F", "ZZ"]); - expectToBeSortedAccordingTo("projectNumber", [1, 3, 5, 10]); - expectToBeSortedAccordingTo("schoolClass", ["AA", "FG", "FH", "I"]); - // cannot test sorting according to age because the setter is inaccessible + expect(router.navigate).toHaveBeenCalledWith([ + `/${Child.ENTITY_TYPE.toLowerCase()}`, + child.getId(), + ]); }); }); From 0481628595adc2937f9fdff7a9a9ecc8624f24df Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 13:02:40 +0200 Subject: [PATCH 116/230] added tests for previousschoolscomponent --- .../children/children.module.ts | 2 - .../children/children.service.ts | 2 +- .../select-group-children.component.html | 58 ------- .../select-group-children.component.scss | 12 -- .../select-group-children.component.spec.ts | 158 ------------------ .../select-group-children.component.ts | 135 --------------- .../note-config.interface.ts | 0 .../previous-schools.component.spec.ts | 31 +++- .../previous-schools.component.ts | 14 +- .../entity-details.component.spec.ts | 4 +- 10 files changed, 34 insertions(+), 382 deletions(-) delete mode 100644 src/app/child-dev-project/children/select-group-children/select-group-children.component.html delete mode 100644 src/app/child-dev-project/children/select-group-children/select-group-children.component.scss delete mode 100644 src/app/child-dev-project/children/select-group-children/select-group-children.component.spec.ts delete mode 100644 src/app/child-dev-project/children/select-group-children/select-group-children.component.ts delete mode 100644 src/app/child-dev-project/notes/note-config-loader/note-config.interface.ts diff --git a/src/app/child-dev-project/children/children.module.ts b/src/app/child-dev-project/children/children.module.ts index a772fa9304..db8d982402 100644 --- a/src/app/child-dev-project/children/children.module.ts +++ b/src/app/child-dev-project/children/children.module.ts @@ -52,7 +52,6 @@ import { HealthCheckupComponent } from "../health-checkup/health-checkup-compone import { MatDatepickerModule } from "@angular/material/datepicker"; import { PreviousSchoolsComponent } from "../previous-schools/previous-schools.component"; import { AdminModule } from "../../core/admin/admin.module"; -import { SelectGroupChildrenComponent } from "./select-group-children/select-group-children.component"; import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; import { RecentNotesDashboardComponent } from "../notes/dashboard-widgets/recent-notes-dashboard/recent-notes-dashboard.component"; import { FormDialogModule } from "../../core/form-dialog/form-dialog.module"; @@ -119,7 +118,6 @@ import { PhotoDatatype } from "./child-photo-service/datatype-photo"; ChildrenCountDashboardComponent, EducationalMaterialComponent, AserComponent, - SelectGroupChildrenComponent, NoRecentNotesDashboardComponent, RecentNotesDashboardComponent, HealthCheckupComponent, diff --git a/src/app/child-dev-project/children/children.service.ts b/src/app/child-dev-project/children/children.service.ts index 46289e5aa2..1b0104f799 100644 --- a/src/app/child-dev-project/children/children.service.ts +++ b/src/app/child-dev-project/children/children.service.ts @@ -462,7 +462,7 @@ export class ChildrenService { }; } - async getSchoolsWithRelations( + async getSchoolRelationsFor( childId: string ): Promise { return await this.querySortedRelations(childId); diff --git a/src/app/child-dev-project/children/select-group-children/select-group-children.component.html b/src/app/child-dev-project/children/select-group-children/select-group-children.component.html deleted file mode 100644 index c7ab6d8b89..0000000000 --- a/src/app/child-dev-project/children/select-group-children/select-group-children.component.html +++ /dev/null @@ -1,58 +0,0 @@ -
-
- - Select center - - - {{ group.label }} - - - -
- -
- - Select school - - - {{ group.label }} - - - - -
- -
- - Select class - - - {{ group.label }} - - - -
- -
Total students selected: {{ value.length }}
- -
- -
-
diff --git a/src/app/child-dev-project/children/select-group-children/select-group-children.component.scss b/src/app/child-dev-project/children/select-group-children/select-group-children.component.scss deleted file mode 100644 index 56e599b817..0000000000 --- a/src/app/child-dev-project/children/select-group-children/select-group-children.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -.group-select-option { - width: 100%; - padding: 16px; - cursor: pointer; - box-sizing: border-box; - border: 1px solid; - border-top: 0; -} - -.group-select-option:first-child { - border-top: 1px solid; -} diff --git a/src/app/child-dev-project/children/select-group-children/select-group-children.component.spec.ts b/src/app/child-dev-project/children/select-group-children/select-group-children.component.spec.ts deleted file mode 100644 index 46d0c8dd93..0000000000 --- a/src/app/child-dev-project/children/select-group-children/select-group-children.component.spec.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; -import { SelectGroupChildrenComponent } from "./select-group-children.component"; -import { ChildrenService } from "../children.service"; -import { BehaviorSubject } from "rxjs"; -import { Child } from "../model/child"; -import { ChildrenModule } from "../children.module"; -import { RouterTestingModule } from "@angular/router/testing"; - -describe("SelectGroupChildrenComponent", () => { - let component: SelectGroupChildrenComponent; - let fixture: ComponentFixture; - - let mockChildrenService; - const mockChildrenObservable = new BehaviorSubject([]); - - beforeEach( - waitForAsync(() => { - mockChildrenService = jasmine.createSpyObj(["getChildren"]); - mockChildrenService.getChildren.and.returnValue(mockChildrenObservable); - - TestBed.configureTestingModule({ - declarations: [SelectGroupChildrenComponent], - imports: [ChildrenModule, RouterTestingModule], - providers: [ - { provide: ChildrenService, useValue: mockChildrenService }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(SelectGroupChildrenComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); - - it("should extract all centers", () => { - const mockChildren = [new Child("0"), new Child("1")]; - mockChildren[0].center = { id: "a", label: "Center A" }; - mockChildren[1].center = { id: "b", label: "Center B" }; - - mockChildrenObservable.next(mockChildren); - - expect(component.centerFilters.options.length).toBe(3); - }); - - it("should extract all schools of selected center", () => { - const selectedCenter = { id: "a", label: "Center A" }; - const mockChildren = [ - new Child("0"), - new Child("1"), - new Child("2"), - new Child("3"), - ]; - mockChildren[0].center = selectedCenter; - mockChildren[0].schoolId = "School:1"; - mockChildren[1].center = selectedCenter; - mockChildren[1].schoolId = "School:2"; - mockChildren[3].center = { id: "c", label: "other center" }; - mockChildren[3].schoolId = "School:3"; - - mockChildrenObservable.next(mockChildren); - - component.selectCenterFilter( - component.centerFilters.options.find( - (o) => o.label === selectedCenter.label - ) - ); - - expect(component.schoolFilters.options.length).toBe(3); // includes default option "all schools" - expect(component.schoolFilters.options[1].key).toBe("School:1"); - expect(component.schoolFilters.options[2].key).toBe("School:2"); - }); - - it("should not list empty filter for undefined schools", () => { - const selectedCenter = { id: "a", label: "Center A" }; - const mockChildren = [new Child("0"), new Child("1")]; - mockChildren[0].center = selectedCenter; - mockChildren[0].schoolId = "School:1"; - mockChildren[1].center = selectedCenter; - // mockChildren[1].schoolId is not set - - mockChildrenObservable.next(mockChildren); - - component.selectCenterFilter( - component.centerFilters.options.find( - (o) => o.label === selectedCenter.label - ) - ); - - expect(component.schoolFilters.options.length).toBe(2); // includes default option "all schools" - expect(component.schoolFilters.options[1].key).toBe("School:1"); - }); - - it("should emit selected children correctly filtered by center and school", () => { - const selectedCenter = { id: "a", label: "Center A" }; - const selectedSchool = "School:1"; - - const mockChildren = [new Child("0"), new Child("1"), new Child("2")]; - mockChildren[0].center = selectedCenter; - mockChildren[0].schoolId = selectedSchool; - mockChildren[1].center = selectedCenter; - // mockChildren[1].schoolId is not set - mockChildren[2].center = { id: "c", label: "other center" }; - mockChildren[2].schoolId = selectedSchool; - - mockChildrenObservable.next(mockChildren); - - spyOn(component.valueChange, "emit"); - - component.selectCenterFilter( - component.centerFilters.options.find( - (o) => o.label === selectedCenter.label - ) - ); - component.selectSchoolFilter( - component.schoolFilters.options.find((o) => o.key === selectedSchool) - ); - component.confirmSelectedChildren(); - - expect(component.valueChange.emit).toHaveBeenCalledWith([mockChildren[0]]); - }); - - it("should emit all children of center for default filter", () => { - const selectedCenter = { id: "a", label: "Center A" }; - - const mockChildren = [new Child("0"), new Child("1"), new Child("2")]; - mockChildren[0].center = selectedCenter; - mockChildren[0].schoolId = "School:1"; - mockChildren[1].center = selectedCenter; - // mockChildren[1].schoolId is not set - mockChildren[2].center = { id: "c", label: "other center" }; - mockChildren[2].schoolId = "School:1"; - - mockChildrenObservable.next(mockChildren); - - spyOn(component.valueChange, "emit"); - - component.selectCenterFilter( - component.centerFilters.options.find( - (o) => o.label === selectedCenter.label - ) - ); - component.selectSchoolFilter( - component.schoolFilters.options.find((o) => o.key === "all") - ); - component.confirmSelectedChildren(); - - expect(component.valueChange.emit).toHaveBeenCalledWith([ - mockChildren[0], - mockChildren[1], - ]); - }); -}); diff --git a/src/app/child-dev-project/children/select-group-children/select-group-children.component.ts b/src/app/child-dev-project/children/select-group-children/select-group-children.component.ts deleted file mode 100644 index 710356f517..0000000000 --- a/src/app/child-dev-project/children/select-group-children/select-group-children.component.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Component, EventEmitter, OnInit, Output } from "@angular/core"; -import { Child } from "../model/child"; -import { ChildrenService } from "../children.service"; -import { - FilterSelection, - FilterSelectionOption, -} from "../../../core/filter/filter-selection/filter-selection"; -import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; - -/** - * Use this component in your template to allow the user to select a group of children. - */ -@UntilDestroy() -@Component({ - selector: "app-select-group-children", - templateUrl: "./select-group-children.component.html", - styleUrls: ["./select-group-children.component.scss"], -}) -export class SelectGroupChildrenComponent implements OnInit { - @Output() valueChange = new EventEmitter(); - value: Child[] = []; - - children: Child[]; - - centerFilters = new FilterSelection("Centers", []); - private selectedCenterFilter: FilterSelectionOption; - - schoolFilters = new FilterSelection("Schools", []); - private selectedSchoolFilter: FilterSelectionOption; - - classFilters = new FilterSelection("Classes", []); - private selectedClassFilter: FilterSelectionOption; - - constructor(private childrenService: ChildrenService) {} - - ngOnInit() { - this.childrenService - .getChildren() - .pipe(untilDestroyed(this)) - .subscribe((children) => { - this.children = children.filter((c) => c.isActive); - this.centerFilters.options = this.loadCenterFilterOptions( - this.children - ); - }); - } - - private loadCenterFilterOptions(children: Child[]) { - const options = [this.getAllStudentsFilterOption()]; - children - .map((c) => c.center) - .forEach((center) => { - if (!center) { - return; - } - - const filterOption = { - key: center.id, - label: center.label, - type: "valueFilter", - filterFun: (c: Child) => c.center === center, - }; - options.push(filterOption); - }); - return options; - } - - private loadFilterOptionsForProperty( - children: Child[], - propertyToBeFiltered: string - ) { - const options = [this.getAllStudentsFilterOption()]; - children - .map((c) => c[propertyToBeFiltered]) - .filter((value, index, arr) => arr.indexOf(value) === index) - .forEach((id) => { - if (!id) { - return; - } - - const filterOption = { - key: id, - label: id, - type: "valueFilter", - filterFun: (c: Child) => c[propertyToBeFiltered] === id, - }; - options.push(filterOption); - }); - return options; - } - - private getAllStudentsFilterOption(): FilterSelectionOption { - return { - key: "all", - label: "All Students", - filterFun: () => true, - }; - } - - selectCenterFilter(group: FilterSelectionOption) { - this.selectedCenterFilter = group; - this.value = this.children.filter(this.selectedCenterFilter.filterFun); - - this.schoolFilters.options = this.loadFilterOptionsForProperty( - this.value, - "schoolId" - ); - this.selectSchoolFilter(this.schoolFilters.options[0]); // reset to the default "All Students" filter - } - - selectSchoolFilter(group: FilterSelectionOption) { - this.selectedSchoolFilter = group; - this.value = this.children - .filter(this.selectedCenterFilter.filterFun) - .filter(this.selectedSchoolFilter.filterFun); - - this.classFilters.options = this.loadFilterOptionsForProperty( - this.value, - "schoolClass" - ); - this.selectClassFilter(this.classFilters.options[0]); // reset to the default "All Students" filter - } - - selectClassFilter(group: FilterSelectionOption) { - this.selectedClassFilter = group; - this.value = this.children - .filter(this.selectedCenterFilter.filterFun) - .filter(this.selectedSchoolFilter.filterFun) - .filter(this.selectedClassFilter.filterFun); - } - - confirmSelectedChildren() { - this.valueChange.emit(this.value); - } -} diff --git a/src/app/child-dev-project/notes/note-config-loader/note-config.interface.ts b/src/app/child-dev-project/notes/note-config-loader/note-config.interface.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts b/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts index c84444fb23..9f73c716c0 100644 --- a/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts +++ b/src/app/child-dev-project/previous-schools/previous-schools.component.spec.ts @@ -16,6 +16,7 @@ import { SimpleChange } from "@angular/core"; import { Child } from "../children/model/child"; import { PanelConfig } from "../../core/entity-components/entity-details/EntityDetailsConfig"; import { ChildSchoolRelation } from "../children/model/childSchoolRelation"; +import moment from "moment"; describe("PreviousSchoolsComponent", () => { let component: PreviousSchoolsComponent; @@ -28,8 +29,8 @@ describe("PreviousSchoolsComponent", () => { beforeEach( waitForAsync(() => { - mockChildrenService = jasmine.createSpyObj(["getSchoolsWithRelations"]); - mockChildrenService.getSchoolsWithRelations.and.resolveTo([ + mockChildrenService = jasmine.createSpyObj(["getSchoolRelationsFor"]); + mockChildrenService.getSchoolRelationsFor.and.resolveTo([ new ChildSchoolRelation(), ]); mockEntityMapper = jasmine.createSpyObj(["loadType"]); @@ -65,7 +66,7 @@ describe("PreviousSchoolsComponent", () => { child: new SimpleChange(undefined, testChild, false), }); tick(); - expect(mockChildrenService.getSchoolsWithRelations).toHaveBeenCalledWith( + expect(mockChildrenService.getSchoolRelationsFor).toHaveBeenCalledWith( testChild.getId() ); })); @@ -76,9 +77,9 @@ describe("PreviousSchoolsComponent", () => { config: { single: true, columns: [ - { id: "schoolId", placeholder: "Team", input: "school" }, - { id: "start", placeholder: "From", input: "date" }, - { id: "end", placeholder: "To", input: "date" }, + { id: "schoolId", placeholder: "Team", view: "school" }, + { id: "start", placeholder: "From", view: "date" }, + { id: "end", placeholder: "To", view: "date" }, ], }, }; @@ -111,4 +112,22 @@ describe("PreviousSchoolsComponent", () => { expect(columnNames).toContain("Class"); expect(columnNames).toContain("Result"); })); + + it("should create new records with preset data", () => { + const existingRelation = new ChildSchoolRelation(); + existingRelation.start = moment().subtract(1, "year").toDate(); + existingRelation.end = moment().subtract(1, "week").toDate(); + component.records = [existingRelation]; + const child = new Child(); + component.child = child; + + const newRelation = component.generateNewRecordFactory()(); + + expect(newRelation.childId).toEqual(child.getId()); + expect( + moment(existingRelation.end) + .add(1, "day") + .isSame(newRelation.start, "day") + ).toBeTrue(); + }); }); diff --git a/src/app/child-dev-project/previous-schools/previous-schools.component.ts b/src/app/child-dev-project/previous-schools/previous-schools.component.ts index cec4885049..3e8793f864 100644 --- a/src/app/child-dev-project/previous-schools/previous-schools.component.ts +++ b/src/app/child-dev-project/previous-schools/previous-schools.component.ts @@ -5,6 +5,7 @@ import { Child } from "../children/model/child"; import { OnInitDynamicComponent } from "../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../core/entity-components/entity-details/EntityDetailsConfig"; import { FormFieldConfig } from "../../core/entity-components/entity-details/form/FormConfig"; +import moment from "moment"; @Component({ selector: "app-previous-schools", @@ -49,7 +50,7 @@ export class PreviousSchoolsComponent return; } - this.records = await this.childrenService.getSchoolsWithRelations(id); + this.records = await this.childrenService.getSchoolRelationsFor(id); this.current = this.records.find((record) => record.isActive); } @@ -58,14 +59,11 @@ export class PreviousSchoolsComponent return () => { const newPreviousSchool = new ChildSchoolRelation(); newPreviousSchool.childId = childId; - // last to-date (of first entry in records); if the first entry doesn't have any to-date, lastToDate is set to yesterday - const lastToDate = + // start is one after the end date of the last relation or today if no other relation exists + newPreviousSchool.start = this.records.length && this.records[0].end - ? new Date(this.records[0].end) - : new Date(new Date().setDate(new Date().getDate() + -1)); - newPreviousSchool.start = new Date( - lastToDate.setDate(lastToDate.getDate() + 1) - ); // one day after last to-date + ? moment(this.records[0].end).add(1, "day").toDate() + : new Date(); return newPreviousSchool; }; } diff --git a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts index ced3c63a05..e9b9746894 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts @@ -69,10 +69,10 @@ describe("EntityDetailsComponent", () => { beforeEach( waitForAsync(() => { mockChildrenService = jasmine.createSpyObj([ - "getSchoolsWithRelations", + "getSchoolRelationsFor", "getAserResultsOfChild", ]); - mockChildrenService.getSchoolsWithRelations.and.resolveTo([]); + mockChildrenService.getSchoolRelationsFor.and.resolveTo([]); mockChildrenService.getAserResultsOfChild.and.returnValue(of([])); mockEntityMapper = jasmine.createSpyObj([ "loadType", From 1816f17719b70d8deb407381155a74fe68907f66 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 13:18:26 +0200 Subject: [PATCH 117/230] added tests for edit percentage component --- .../edit-percentage.component.spec.ts | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts index ad65acae6a..6d023ad581 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts @@ -2,7 +2,12 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { EditPercentageComponent } from "./edit-percentage.component"; import { MatFormFieldModule } from "@angular/material/form-field"; -import { FormControl } from "@angular/forms"; +import { + FormControl, + FormGroup, + ReactiveFormsModule, + Validators, +} from "@angular/forms"; import { MatInputModule } from "@angular/material/input"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; @@ -12,7 +17,12 @@ describe("EditPercentageComponent", () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [MatFormFieldModule, MatInputModule, NoopAnimationsModule], + imports: [ + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + NoopAnimationsModule, + ], declarations: [EditPercentageComponent], }).compileComponents(); }); @@ -20,11 +30,53 @@ describe("EditPercentageComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(EditPercentageComponent); component = fixture.componentInstance; - component.formControl = new FormControl(); + const formControl = new FormControl(); + new FormGroup({ testProperty: formControl }); + component.onInitFromDynamicConfig({ + formControl: formControl, + propertySchema: {}, + formFieldConfig: { id: "testProperty" }, + }); fixture.detectChanges(); }); it("should create", () => { expect(component).toBeTruthy(); }); + + it("should only allow valid percentage values", () => { + component.formControl.setValue(101); + expect(component.formControl.invalid).toBeTrue(); + + component.formControl.setValue(100); + expect(component.formControl.valid).toBeTrue(); + + component.formControl.setValue(10); + expect(component.formControl.valid).toBeTrue(); + + component.formControl.setValue(0); + expect(component.formControl.valid).toBeTrue(); + + component.formControl.setValue(-1); + expect(component.formControl.invalid).toBeTrue(); + + component.formControl.setValue("one" as any); + expect(component.formControl.invalid).toBeTrue(); + }); + + it("should keep existing validators", () => { + component.formControl.setValue(null); + expect(component.formControl.valid).toBeTrue(); + + const control = new FormControl(0, [Validators.required]); + new FormGroup({ testProperty: control }); + component.onInitFromDynamicConfig({ + formControl: control, + propertySchema: {}, + formFieldConfig: { id: "testProperty" }, + }); + + component.formControl.setValue(null); + expect(component.formControl.invalid).toBeTrue(); + }); }); From 581c88f541b8a8f1540f18604fdacf5b8780e56f Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 13:22:11 +0200 Subject: [PATCH 118/230] added test for edit photo component --- .../edit-photo/edit-photo.component.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts index 54acbfdd61..8022e939f8 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts @@ -36,4 +36,10 @@ describe("EditPhotoComponent", () => { it("should create", () => { expect(component).toBeTruthy(); }); + + it("should correctly update the photo path", () => { + component.changeFilename("new_file.name"); + + expect(component.formControl.value.path).toBe("new_file.name"); + }); }); From 5df742d69974bd27d92ec5c60dabb3176a7fef1e Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 13:28:11 +0200 Subject: [PATCH 119/230] moved view-components to entity subrecord --- .../entity-form/entity-form.module.ts | 2 - .../entity-select/entity-select.module.ts | 2 - .../entity-subrecord.module.ts | 34 +++++++++++++++- .../display-checkmark.component.spec.ts | 0 .../display-checkmark.component.ts | 0 ...isplay-configurable-enum.component.spec.ts | 0 .../display-configurable-enum.component.ts | 0 .../display-date.component.spec.ts | 0 .../display-date/display-date.component.ts | 0 .../display-entity-array.component.html | 0 .../display-entity-array.component.scss | 0 .../display-entity-array.component.spec.ts | 0 .../display-entity-array.component.ts | 0 .../display-entity-array.stories.ts | 4 +- .../display-entity.component.html | 0 .../display-entity.component.scss | 0 .../display-entity.component.spec.ts | 0 .../display-entity.component.ts | 0 .../display-entity/display-entity.stories.ts | 4 +- .../display-percentage.component.html | 0 .../display-percentage.component.scss | 0 .../display-percentage.component.spec.ts | 0 .../display-percentage.component.ts | 0 .../display-text.component.spec.ts | 0 .../display-text/display-text.component.ts | 0 .../display-unit/display-unit.component.html | 0 .../display-unit/display-unit.component.scss | 0 .../display-unit.component.spec.ts | 0 .../display-unit/display-unit.component.ts | 0 .../readonly-function.component.html | 0 .../readonly-function.component.scss | 0 .../readonly-function.component.spec.ts | 0 .../readonly-function.component.ts | 0 .../view-components/view-component.ts | 0 .../entity-utils/entity-utils.module.ts | 40 ------------------- src/app/core/view/dynamic-components-map.ts | 18 ++++----- 36 files changed, 46 insertions(+), 58 deletions(-) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-checkmark/display-checkmark.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-checkmark/display-checkmark.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-configurable-enum/display-configurable-enum.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-date/display-date.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-date/display-date.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity-array/display-entity-array.component.html (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity-array/display-entity-array.component.scss (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity-array/display-entity-array.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity-array/display-entity-array.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity-array/display-entity-array.stories.ts (96%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity/display-entity.component.html (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity/display-entity.component.scss (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity/display-entity.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity/display-entity.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-entity/display-entity.stories.ts (96%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-percentage/display-percentage.component.html (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-percentage/display-percentage.component.scss (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-percentage/display-percentage.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-percentage/display-percentage.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-text/display-text.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-text/display-text.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-unit/display-unit.component.html (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-unit/display-unit.component.scss (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-unit/display-unit.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/display-unit/display-unit.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/readonly-function/readonly-function.component.html (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/readonly-function/readonly-function.component.scss (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/readonly-function/readonly-function.component.spec.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/readonly-function/readonly-function.component.ts (100%) rename src/app/core/entity-components/{entity-utils => entity-subrecord}/view-components/view-component.ts (100%) delete mode 100644 src/app/core/entity-components/entity-utils/entity-utils.module.ts diff --git a/src/app/core/entity-components/entity-form/entity-form.module.ts b/src/app/core/entity-components/entity-form/entity-form.module.ts index 81b1920d6e..a394d10ac4 100644 --- a/src/app/core/entity-components/entity-form/entity-form.module.ts +++ b/src/app/core/entity-components/entity-form/entity-form.module.ts @@ -22,7 +22,6 @@ import { AlertsModule } from "../../alerts/alerts.module"; import { EditEntityArrayComponent } from "./dynamic-form-components/edit-entity-array/edit-entity-array.component"; import { EntitySelectModule } from "../entity-select/entity-select.module"; import { EditSingleEntityComponent } from "./dynamic-form-components/edit-single-entity/edit-single-entity.component"; -import { EntityUtilsModule } from "../entity-utils/entity-utils.module"; import { EditPercentageComponent } from "./dynamic-form-components/edit-percentage/edit-percentage.component"; @NgModule({ @@ -53,7 +52,6 @@ import { EditPercentageComponent } from "./dynamic-form-components/edit-percenta MatNativeDateModule, AlertsModule, EntitySelectModule, - EntityUtilsModule, ], entryComponents: [ EditConfigurableEnumComponent, diff --git a/src/app/core/entity-components/entity-select/entity-select.module.ts b/src/app/core/entity-components/entity-select/entity-select.module.ts index a6badcb71a..2e8220baa9 100644 --- a/src/app/core/entity-components/entity-select/entity-select.module.ts +++ b/src/app/core/entity-components/entity-select/entity-select.module.ts @@ -8,7 +8,6 @@ import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatInputModule } from "@angular/material/input"; import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; -import { EntityUtilsModule } from "../entity-utils/entity-utils.module"; @NgModule({ declarations: [EntitySelectComponent], @@ -21,7 +20,6 @@ import { EntityUtilsModule } from "../entity-utils/entity-utils.module"; MatInputModule, MatTooltipModule, ViewModule, - EntityUtilsModule, ], exports: [EntitySelectComponent], }) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 2b6119456a..a49b12ce21 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -19,9 +19,30 @@ import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; import { EntityFormModule } from "../entity-form/entity-form.module"; import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; +import { DisplayEntityComponent } from "./view-components/display-entity/display-entity.component"; +import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; +import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; +import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; +import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; +import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; +import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; +import { DisplayUnitComponent } from "./view-components/display-unit/display-unit.component"; @NgModule({ - declarations: [EntitySubrecordComponent, KeysPipe], + declarations: [ + EntitySubrecordComponent, + KeysPipe, + DisplayEntityComponent, + DisplayEntityArrayComponent, + DisplayTextComponent, + DisplayDateComponent, + DisplayConfigurableEnumComponent, + DisplayCheckmarkComponent, + ReadonlyFunctionComponent, + DisplayPercentageComponent, + DisplayUnitComponent, + ], imports: [ CommonModule, AlertsModule, @@ -43,5 +64,16 @@ import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation ConfirmationDialogModule, ], exports: [EntitySubrecordComponent, KeysPipe], + entryComponents: [ + DisplayEntityComponent, + DisplayEntityArrayComponent, + DisplayTextComponent, + DisplayDateComponent, + DisplayConfigurableEnumComponent, + DisplayCheckmarkComponent, + ReadonlyFunctionComponent, + DisplayPercentageComponent, + DisplayUnitComponent, + ], }) export class EntitySubrecordModule {} diff --git a/src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.scss b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.scss rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.scss diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts similarity index 96% rename from src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts index 1712cb1c0e..d676d11e88 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts @@ -1,7 +1,6 @@ import { Story, Meta } from "@storybook/angular/types-6-0"; import { moduleMetadata } from "@storybook/angular"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { EntityUtilsModule } from "../../entity-utils.module"; import { Child } from "../../../../../child-dev-project/children/model/child"; import { Database } from "../../../../database/database"; import { BackupService } from "../../../../admin/services/backup.service"; @@ -13,6 +12,7 @@ import { SchoolsModule } from "../../../../../child-dev-project/schools/schools. import { ChildrenModule } from "../../../../../child-dev-project/children/children.module"; import { DisplayEntityArrayComponent } from "./display-entity-array.component"; import { BehaviorSubject } from "rxjs"; +import { EntitySubrecordModule } from "../../entity-subrecord.module"; const child1 = new Child(); child1.name = "Test Name"; @@ -56,7 +56,7 @@ export default { decorators: [ moduleMetadata({ imports: [ - EntityUtilsModule, + EntitySubrecordModule, NoopAnimationsModule, RouterTestingModule, SchoolsModule, diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.scss b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.scss rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.scss diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts similarity index 96% rename from src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts index e84eb348a5..d216813199 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts @@ -1,7 +1,6 @@ import { Story, Meta } from "@storybook/angular/types-6-0"; import { moduleMetadata } from "@storybook/angular"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { EntityUtilsModule } from "../../entity-utils.module"; import { DisplayEntityComponent } from "./display-entity.component"; import { Child } from "../../../../../child-dev-project/children/model/child"; import { Database } from "../../../../database/database"; @@ -15,6 +14,7 @@ import { RouterTestingModule } from "@angular/router/testing"; import { User } from "../../../../user/user"; import { SchoolsModule } from "../../../../../child-dev-project/schools/schools.module"; import { ChildrenModule } from "../../../../../child-dev-project/children/children.module"; +import { EntitySubrecordModule } from "../../entity-subrecord.module"; export default { title: "Core/EntityComponents/DisplayEntity", @@ -22,7 +22,7 @@ export default { decorators: [ moduleMetadata({ imports: [ - EntityUtilsModule, + EntitySubrecordModule, NoopAnimationsModule, RouterTestingModule, SchoolsModule, diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html rename to src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.html diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.scss b/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.scss rename to src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.scss diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.html rename to src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.html diff --git a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.scss b/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.scss rename to src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.scss diff --git a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html b/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html rename to src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.html diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.scss b/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.scss rename to src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.scss diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.spec.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.ts diff --git a/src/app/core/entity-components/entity-utils/view-components/view-component.ts b/src/app/core/entity-components/entity-subrecord/view-components/view-component.ts similarity index 100% rename from src/app/core/entity-components/entity-utils/view-components/view-component.ts rename to src/app/core/entity-components/entity-subrecord/view-components/view-component.ts diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts deleted file mode 100644 index dd90d33c94..0000000000 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; -import { DisplayEntityComponent } from "./view-components/display-entity/display-entity.component"; -import { ViewModule } from "../../view/view.module"; -import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; -import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; -import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; -import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; -import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; -import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; -import { DisplayUnitComponent } from "./view-components/display-unit/display-unit.component"; - -@NgModule({ - declarations: [ - DisplayEntityComponent, - DisplayEntityArrayComponent, - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], - imports: [CommonModule, ViewModule], - entryComponents: [ - DisplayEntityComponent, - DisplayEntityArrayComponent, - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], - exports: [DisplayEntityComponent], -}) -export class EntityUtilsModule {} diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 6331bbf9c3..c5556ea6cf 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -13,10 +13,10 @@ import { RecentAttendanceBlocksComponent } from "../../child-dev-project/childre import { ChildrenOverviewComponent } from "../../child-dev-project/schools/children-overview/children-overview.component"; import { ChildBlockComponent } from "../../child-dev-project/children/child-block/child-block.component"; import { FormComponent } from "../entity-components/entity-details/form/form.component"; -import { DisplayTextComponent } from "../entity-components/entity-utils/view-components/display-text/display-text.component"; -import { DisplayCheckmarkComponent } from "../entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component"; -import { DisplayDateComponent } from "../entity-components/entity-utils/view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayTextComponent } from "../entity-components/entity-subrecord/view-components/display-text/display-text.component"; +import { DisplayCheckmarkComponent } from "../entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component"; +import { DisplayDateComponent } from "../entity-components/entity-subrecord/view-components/display-date/display-date.component"; +import { DisplayConfigurableEnumComponent } from "../entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component"; import { ActivityParticipantsSectionComponent } from "../../child-dev-project/attendance/activity-participants-section/activity-participants-section.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; @@ -32,15 +32,15 @@ import { EditAgeComponent } from "../entity-components/entity-form/dynamic-form- import { EditBooleanComponent } from "../entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "../entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component"; import { EditPhotoComponent } from "../entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component"; -import { ReadonlyFunctionComponent } from "../entity-components/entity-utils/view-components/readonly-function/readonly-function.component"; +import { ReadonlyFunctionComponent } from "../entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component"; import { EditEntityArrayComponent } from "../entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component"; import { SchoolBlockComponent } from "../../child-dev-project/schools/school-block/school-block.component"; -import { DisplayEntityComponent } from "../entity-components/entity-utils/view-components/display-entity/display-entity.component"; +import { DisplayEntityComponent } from "../entity-components/entity-subrecord/view-components/display-entity/display-entity.component"; import { EditSingleEntityComponent } from "../entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component"; -import { DisplayEntityArrayComponent } from "../entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component"; +import { DisplayEntityArrayComponent } from "../entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component"; import { EditPercentageComponent } from "../entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component"; -import { DisplayPercentageComponent } from "../entity-components/entity-utils/view-components/display-percentage/display-percentage.component"; -import { DisplayUnitComponent } from "../entity-components/entity-utils/view-components/display-unit/display-unit.component"; +import { DisplayPercentageComponent } from "../entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component"; +import { DisplayUnitComponent } from "../entity-components/entity-subrecord/view-components/display-unit/display-unit.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], From 516669561486e6d79177e0e9730aea8ee5d7f4e6 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 13:51:43 +0200 Subject: [PATCH 120/230] added tests for display entity component --- .../entity-subrecord.module.ts | 2 +- .../display-entity-array.component.html | 2 +- .../display-entity-array.component.ts | 2 +- .../display-entity.component.spec.ts | 22 ++++++++++++++++++- .../display-entity.component.ts | 22 +++++++++++-------- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index a49b12ce21..e6b66c3b2d 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -63,7 +63,7 @@ import { DisplayUnitComponent } from "./view-components/display-unit/display-uni EntityFormModule, ConfirmationDialogModule, ], - exports: [EntitySubrecordComponent, KeysPipe], + exports: [EntitySubrecordComponent, KeysPipe, DisplayEntityComponent], entryComponents: [ DisplayEntityComponent, DisplayEntityArrayComponent, diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html index 9d1ac3e18b..ff5a2971d7 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html @@ -1,4 +1,4 @@ - + {{ entities.length }} in total diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts index b65da130f4..dced2e1ad0 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts @@ -18,7 +18,7 @@ export class DisplayEntityArrayComponent extends ViewComponent { async onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); - const entityType = config.entity.getSchema().get(this.property).ext; + const entityType = this.entity.getSchema().get(this.property).ext; const entityConstructor = ENTITY_MAP.get(entityType); if (!entityConstructor) { throw new Error(`Could not find type ${entityType} in ENTITY_MAP`); diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts index adc40d330f..834f65afc1 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts @@ -1,8 +1,15 @@ -import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { + ComponentFixture, + fakeAsync, + TestBed, + tick, +} from "@angular/core/testing"; import { DisplayEntityComponent } from "./display-entity.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { Child } from "../../../../../child-dev-project/children/model/child"; +import { ChildSchoolRelation } from "../../../../../child-dev-project/children/model/childSchoolRelation"; +import { School } from "../../../../../child-dev-project/schools/model/school"; describe("DisplayEntityComponent", () => { let component: DisplayEntityComponent; @@ -27,4 +34,17 @@ describe("DisplayEntityComponent", () => { it("should create", () => { expect(component).toBeTruthy(); }); + + it("should use the block component when available", fakeAsync(() => { + const school = new School(); + mockEntityMapper.load.and.resolveTo(school); + component.onInitFromDynamicConfig({ + entity: new ChildSchoolRelation(), + id: "schoolId", + }); + tick(); + + expect(component.entityBlockComponent).toEqual(School.getBlockComponent()); + expect(component.entityToDisplay).toEqual(school); + })); }); diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts index ee70357a2b..057254f330 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts @@ -1,37 +1,41 @@ import { Component, Input, OnInit } from "@angular/core"; import { Entity } from "../../../../entity/entity"; -import { OnInitDynamicComponent } from "../../../../view/dynamic-components/on-init-dynamic-component.interface"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; +import { ViewComponent } from "../view-component"; @Component({ selector: "app-display-entity", templateUrl: "./display-entity.component.html", styleUrls: ["./display-entity.component.scss"], }) -export class DisplayEntityComponent implements OnInit, OnInitDynamicComponent { - @Input() entity: Entity; +export class DisplayEntityComponent extends ViewComponent implements OnInit { + @Input() entityToDisplay: Entity; @Input() linkDisabled = false; entityBlockComponent: string; - constructor(private entityMapper: EntityMapperService) {} + constructor(private entityMapper: EntityMapperService) { + super(); + } ngOnInit(): void { - if (this.entity) { - this.entityBlockComponent = this.entity + if (this.entityToDisplay) { + this.entityBlockComponent = this.entityToDisplay .getConstructor() .getBlockComponent(); } } async onInitFromDynamicConfig(config: ViewPropertyConfig) { - const type = config.config || config.entity.getSchema().get(config.id).ext; + super.onInitFromDynamicConfig(config); + const type = + config.config || this.entity.getSchema().get(this.property).ext; const entityConstructor = ENTITY_MAP.get(type); if (!entityConstructor) { throw new Error(`Could not find type ${type} in ENTITY_MAP`); } - this.entity = await this.entityMapper - .load(entityConstructor, config.entity[config.id]) + this.entityToDisplay = await this.entityMapper + .load(entityConstructor, this.entity[this.property]) .catch(() => null); this.ngOnInit(); } From 8dd0505041ee6e409b73a84f0c74160337c54f2d Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 14:13:12 +0200 Subject: [PATCH 121/230] fixed display entity component --- .../display-entity/display-entity.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html index 42b409d37c..274e726955 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html +++ b/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html @@ -1,14 +1,14 @@ - - {{entity["name"] || entity.getId()}} + + {{entityToDisplay["name"] || entityToDisplay.getId()}} From c3ed0d8e1ef4516953736a35a2dde6db3f17594d Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 14:16:59 +0200 Subject: [PATCH 122/230] using form component to edit recurring activity participatns and groups --- .../attendance/model/recurring-activity.ts | 18 ++++++++++++++++-- src/app/core/config/config-fix.ts | 8 +++++++- .../edit-single-entity.component.html | 2 +- .../entity-select/entity-select.component.html | 8 +++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.ts b/src/app/child-dev-project/attendance/model/recurring-activity.ts index 8eae45513a..3b01624417 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.ts @@ -24,6 +24,8 @@ import { InteractionType, } from "../../notes/model/interaction-type.interface"; import { User } from "../../../core/user/user"; +import { Child } from "../../children/model/child"; +import { School } from "../../schools/model/school"; @DatabaseEntity("RecurringActivity") export class RecurringActivity extends Entity { @@ -57,10 +59,22 @@ export class RecurringActivity extends Entity { type: InteractionType; /** IDs of children linked to this activity */ - @DatabaseField() participants: string[] = []; + @DatabaseField({ + label: "Participants", + viewComponent: "DisplayEntityArray", + editComponent: "EditEntityArray", + ext: Child.ENTITY_TYPE, + }) + participants: string[] = []; /** IDs of groups (schools, teams) whose (active) members should be included in the activity*/ - @DatabaseField() linkedGroups: string[] = []; + @DatabaseField({ + label: "Schools", + viewComponent: "DisplayEntityArray", + editComponent: "EditEntityArray", + ext: School.ENTITY_TYPE, + }) + linkedGroups: string[] = []; /** IDs of the users who are responsible for conducting this activity */ @DatabaseField({ diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index c01e925297..69c9e89fbd 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -722,7 +722,13 @@ export const defaultJsonConfig = { "title": "Participants", "components": [ { - "component": "ActivityParticipantsSection" + "component": "Form", + "config": { + "cols": [[ + { "id": "linkedGroups" }, + { "id": "participants" } + ]] + } } ] }, diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html index 15ec710c02..726df813f3 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html +++ b/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html @@ -2,7 +2,7 @@ {{ placeholder }} - + diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html b/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html index 2cb8b57d81..6fcccfffbd 100644 --- a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html +++ b/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html @@ -20,8 +20,10 @@ [removable]="removable && formControl.enabled" *ngFor="let entity of selection_" class="chip"> +

{{entity["name"]}}

+ - +
- - +

{{res["name"]}}

+
From 9d4149f08e78ac2d08559247d9e978b7c25a5b08 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 14:33:35 +0200 Subject: [PATCH 123/230] moved all view and edit components to entity utils modul --- src/app/app.module.ts | 2 + .../entity-form/entity-form.module.ts | 66 +------------ .../entity-subrecord.module.ts | 50 +--------- .../edit-age/edit-age.component.html | 0 .../edit-age/edit-age.component.scss | 0 .../edit-age/edit-age.component.spec.ts | 0 .../edit-age/edit-age.component.ts | 0 .../edit-boolean/edit-boolean.component.html | 0 .../edit-boolean/edit-boolean.component.scss | 0 .../edit-boolean.component.spec.ts | 0 .../edit-boolean/edit-boolean.component.ts | 0 .../dynamic-form-components/edit-component.ts | 0 .../edit-configurable-enum.component.html | 0 .../edit-configurable-enum.component.scss | 0 .../edit-configurable-enum.component.spec.ts | 0 .../edit-configurable-enum.component.ts | 0 .../edit-date/edit-date.component.html | 0 .../edit-date/edit-date.component.scss | 0 .../edit-date/edit-date.component.spec.ts | 0 .../edit-date/edit-date.component.ts | 0 .../edit-entity-array.component.html | 0 .../edit-entity-array.component.scss | 0 .../edit-entity-array.component.spec.ts | 0 .../edit-entity-array.component.ts | 0 .../edit-long-text.component.html | 0 .../edit-long-text.component.scss | 0 .../edit-long-text.component.spec.ts | 0 .../edit-long-text.component.ts | 0 .../edit-percentage.component.html | 0 .../edit-percentage.component.scss | 0 .../edit-percentage.component.spec.ts | 0 .../edit-percentage.component.ts | 0 .../edit-photo/edit-photo.component.html | 0 .../edit-photo/edit-photo.component.scss | 0 .../edit-photo/edit-photo.component.spec.ts | 0 .../edit-photo/edit-photo.component.ts | 0 .../edit-selectable.component.html | 0 .../edit-selectable.component.scss | 0 .../edit-selectable.component.spec.ts | 0 .../edit-selectable.component.ts | 0 .../edit-single-entity.component.html | 0 .../edit-single-entity.component.scss | 0 .../edit-single-entity.component.spec.ts | 11 ++- .../edit-single-entity.component.ts | 0 .../edit-text/edit-text.component.html | 0 .../edit-text/edit-text.component.scss | 0 .../edit-text/edit-text.component.spec.ts | 0 .../edit-text/edit-text.component.ts | 0 .../entity-utils/entity-utils.module.ts | 95 +++++++++++++++++++ .../display-checkmark.component.spec.ts | 0 .../display-checkmark.component.ts | 0 ...isplay-configurable-enum.component.spec.ts | 0 .../display-configurable-enum.component.ts | 0 .../display-date.component.spec.ts | 0 .../display-date/display-date.component.ts | 0 .../display-entity-array.component.html | 0 .../display-entity-array.component.scss | 0 .../display-entity-array.component.spec.ts | 0 .../display-entity-array.component.ts | 0 .../display-entity-array.stories.ts | 2 +- .../display-entity.component.html | 0 .../display-entity.component.scss | 0 .../display-entity.component.spec.ts | 0 .../display-entity.component.ts | 0 .../display-entity/display-entity.stories.ts | 2 +- .../display-percentage.component.html | 0 .../display-percentage.component.scss | 0 .../display-percentage.component.spec.ts | 0 .../display-percentage.component.ts | 0 .../display-text.component.spec.ts | 0 .../display-text/display-text.component.ts | 0 .../display-unit/display-unit.component.html | 0 .../display-unit/display-unit.component.scss | 0 .../display-unit.component.spec.ts | 0 .../display-unit/display-unit.component.ts | 0 .../readonly-function.component.html | 0 .../readonly-function.component.scss | 0 .../readonly-function.component.spec.ts | 0 .../readonly-function.component.ts | 0 .../view-components/view-component.ts | 0 src/app/core/view/dynamic-components-map.ts | 40 ++++---- 81 files changed, 134 insertions(+), 134 deletions(-) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-age/edit-age.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-age/edit-age.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-age/edit-age.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-age/edit-age.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-boolean/edit-boolean.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-boolean/edit-boolean.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-boolean/edit-boolean.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-boolean/edit-boolean.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-date/edit-date.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-date/edit-date.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-date/edit-date.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-date/edit-date.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-entity-array/edit-entity-array.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-entity-array/edit-entity-array.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-long-text/edit-long-text.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-long-text/edit-long-text.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-long-text/edit-long-text.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-long-text/edit-long-text.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-percentage/edit-percentage.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-percentage/edit-percentage.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-percentage/edit-percentage.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-photo/edit-photo.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-photo/edit-photo.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-photo/edit-photo.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-photo/edit-photo.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-selectable/edit-selectable.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-selectable/edit-selectable.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-selectable/edit-selectable.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-single-entity/edit-single-entity.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-single-entity/edit-single-entity.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts (90%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-text/edit-text.component.html (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-text/edit-text.component.scss (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-text/edit-text.component.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/dynamic-form-components/edit-text/edit-text.component.ts (100%) create mode 100644 src/app/core/entity-components/entity-utils/entity-utils.module.ts rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-checkmark/display-checkmark.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-checkmark/display-checkmark.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-configurable-enum/display-configurable-enum.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-date/display-date.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-date/display-date.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity-array/display-entity-array.component.html (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity-array/display-entity-array.component.scss (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity-array/display-entity-array.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity-array/display-entity-array.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity-array/display-entity-array.stories.ts (96%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity/display-entity.component.html (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity/display-entity.component.scss (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity/display-entity.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity/display-entity.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-entity/display-entity.stories.ts (96%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-percentage/display-percentage.component.html (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-percentage/display-percentage.component.scss (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-percentage/display-percentage.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-percentage/display-percentage.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-text/display-text.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-text/display-text.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-unit/display-unit.component.html (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-unit/display-unit.component.scss (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-unit/display-unit.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/display-unit/display-unit.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/readonly-function/readonly-function.component.html (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/readonly-function/readonly-function.component.scss (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/readonly-function/readonly-function.component.spec.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/readonly-function/readonly-function.component.ts (100%) rename src/app/core/entity-components/{entity-subrecord => entity-utils}/view-components/view-component.ts (100%) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 307682ba3c..3baa1464d3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -72,6 +72,7 @@ import { DemoActivityEventsGeneratorService } from "./child-dev-project/attendan import { ReportingModule } from "./features/reporting/reporting.module"; import { DashboardShortcutWidgetModule } from "./core/dashboard-shortcut-widget/dashboard-shortcut-widget.module"; import { HistoricalDataModule } from "./features/historical-data/historical-data.module"; +import { EntityUtilsModule } from "./core/entity-components/entity-utils/entity-utils.module"; /** * Main entry point of the application. @@ -118,6 +119,7 @@ import { HistoricalDataModule } from "./features/historical-data/historical-data EntityDetailsModule, ConfigurableEnumModule, ReportingModule, + EntityUtilsModule, DemoDataModule.forRoot([ ...DemoChildGenerator.provider({ count: 120 }), ...DemoSchoolGenerator.provider({ count: 8 }), diff --git a/src/app/core/entity-components/entity-form/entity-form.module.ts b/src/app/core/entity-components/entity-form/entity-form.module.ts index a394d10ac4..a606d2f5c6 100644 --- a/src/app/core/entity-components/entity-form/entity-form.module.ts +++ b/src/app/core/entity-components/entity-form/entity-form.module.ts @@ -1,70 +1,8 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; -import { EditConfigurableEnumComponent } from "./dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; -import { EditTextComponent } from "./dynamic-form-components/edit-text/edit-text.component"; -import { EditDateComponent } from "./dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "./dynamic-form-components/edit-selectable/edit-selectable.component"; -import { EditAgeComponent } from "./dynamic-form-components/edit-age/edit-age.component"; -import { EditBooleanComponent } from "./dynamic-form-components/edit-boolean/edit-boolean.component"; -import { EditLongTextComponent } from "./dynamic-form-components/edit-long-text/edit-long-text.component"; -import { EditPhotoComponent } from "./dynamic-form-components/edit-photo/edit-photo.component"; -import { MatFormFieldModule } from "@angular/material/form-field"; -import { ReactiveFormsModule } from "@angular/forms"; -import { MatSelectModule } from "@angular/material/select"; -import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; -import { MatTooltipModule } from "@angular/material/tooltip"; -import { MatIconModule } from "@angular/material/icon"; -import { MatDatepickerModule } from "@angular/material/datepicker"; -import { MatCheckboxModule } from "@angular/material/checkbox"; -import { MatInputModule } from "@angular/material/input"; -import { MatNativeDateModule } from "@angular/material/core"; -import { AlertsModule } from "../../alerts/alerts.module"; -import { EditEntityArrayComponent } from "./dynamic-form-components/edit-entity-array/edit-entity-array.component"; -import { EntitySelectModule } from "../entity-select/entity-select.module"; -import { EditSingleEntityComponent } from "./dynamic-form-components/edit-single-entity/edit-single-entity.component"; -import { EditPercentageComponent } from "./dynamic-form-components/edit-percentage/edit-percentage.component"; @NgModule({ - declarations: [ - EditConfigurableEnumComponent, - EditTextComponent, - EditDateComponent, - EditSelectableComponent, - EditAgeComponent, - EditBooleanComponent, - EditLongTextComponent, - EditPhotoComponent, - EditEntityArrayComponent, - EditSingleEntityComponent, - EditPercentageComponent, - ], - imports: [ - CommonModule, - MatFormFieldModule, - ReactiveFormsModule, - MatSelectModule, - ConfigurableEnumModule, - MatTooltipModule, - MatIconModule, - MatDatepickerModule, - MatCheckboxModule, - MatInputModule, - MatNativeDateModule, - AlertsModule, - EntitySelectModule, - ], - entryComponents: [ - EditConfigurableEnumComponent, - EditTextComponent, - EditDateComponent, - EditSelectableComponent, - EditAgeComponent, - EditBooleanComponent, - EditLongTextComponent, - EditPhotoComponent, - EditEntityArrayComponent, - EditSingleEntityComponent, - EditPercentageComponent, - ], + declarations: [], + imports: [CommonModule], }) export class EntityFormModule {} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index e6b66c3b2d..7cd79e91a5 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -5,10 +5,6 @@ import { KeysPipe } from "./keys-pipe/keys.pipe"; import { MatTableModule } from "@angular/material/table"; import { MatSortModule } from "@angular/material/sort"; import { MatPaginatorModule } from "@angular/material/paginator"; -import { MatInputModule } from "@angular/material/input"; -import { MatDatepickerModule } from "@angular/material/datepicker"; -import { MatSelectModule } from "@angular/material/select"; -import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatIconModule } from "@angular/material/icon"; import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; @@ -19,30 +15,9 @@ import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; import { EntityFormModule } from "../entity-form/entity-form.module"; import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; -import { DisplayEntityComponent } from "./view-components/display-entity/display-entity.component"; -import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; -import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; -import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; -import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; -import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; -import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; -import { DisplayUnitComponent } from "./view-components/display-unit/display-unit.component"; @NgModule({ - declarations: [ - EntitySubrecordComponent, - KeysPipe, - DisplayEntityComponent, - DisplayEntityArrayComponent, - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], + declarations: [EntitySubrecordComponent, KeysPipe], imports: [ CommonModule, AlertsModule, @@ -51,29 +26,14 @@ import { DisplayUnitComponent } from "./view-components/display-unit/display-uni MatTableModule, MatPaginatorModule, MatSortModule, - MatInputModule, - MatDatepickerModule, - MatSelectModule, - MatAutocompleteModule, - MatIconModule, - MatButtonModule, - MatTooltipModule, ViewModule, ReactiveFormsModule, EntityFormModule, ConfirmationDialogModule, + MatTooltipModule, + MatButtonModule, + MatIconModule, ], - exports: [EntitySubrecordComponent, KeysPipe, DisplayEntityComponent], - entryComponents: [ - DisplayEntityComponent, - DisplayEntityArrayComponent, - DisplayTextComponent, - DisplayDateComponent, - DisplayConfigurableEnumComponent, - DisplayCheckmarkComponent, - ReadonlyFunctionComponent, - DisplayPercentageComponent, - DisplayUnitComponent, - ], + exports: [EntitySubrecordComponent, KeysPipe], }) export class EntitySubrecordModule {} diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts similarity index 90% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts index 01017eaa48..c947117aa5 100644 --- a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts @@ -1,11 +1,16 @@ -import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing"; +import { + ComponentFixture, + fakeAsync, + TestBed, + tick, +} from "@angular/core/testing"; import { EditSingleEntityComponent } from "./edit-single-entity.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; -import { EntityFormModule } from "../../entity-form.module"; +import { EntityFormModule } from "../../../entity-form/entity-form.module"; import { FormControl } from "@angular/forms"; import { EntitySchemaService } from "../../../../entity/schema/entity-schema.service"; -import { EntityFormService } from "../../entity-form.service"; +import { EntityFormService } from "../../../entity-form/entity-form.service"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { ChildSchoolRelation } from "../../../../../child-dev-project/children/model/childSchoolRelation"; import { School } from "../../../../../child-dev-project/schools/model/school"; diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.html similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.html rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.html diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.scss similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.scss diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.spec.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.spec.ts diff --git a/src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.ts similarity index 100% rename from src/app/core/entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component.ts rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component.ts diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts new file mode 100644 index 0000000000..dbad06741b --- /dev/null +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -0,0 +1,95 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { EditConfigurableEnumComponent } from "./dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditTextComponent } from "./dynamic-form-components/edit-text/edit-text.component"; +import { EditDateComponent } from "./dynamic-form-components/edit-date/edit-date.component"; +import { EditSelectableComponent } from "./dynamic-form-components/edit-selectable/edit-selectable.component"; +import { EditAgeComponent } from "./dynamic-form-components/edit-age/edit-age.component"; +import { EditBooleanComponent } from "./dynamic-form-components/edit-boolean/edit-boolean.component"; +import { EditLongTextComponent } from "./dynamic-form-components/edit-long-text/edit-long-text.component"; +import { EditPhotoComponent } from "./dynamic-form-components/edit-photo/edit-photo.component"; +import { EditEntityArrayComponent } from "./dynamic-form-components/edit-entity-array/edit-entity-array.component"; +import { EditSingleEntityComponent } from "./dynamic-form-components/edit-single-entity/edit-single-entity.component"; +import { EditPercentageComponent } from "./dynamic-form-components/edit-percentage/edit-percentage.component"; +import { DisplayEntityComponent } from "./view-components/display-entity/display-entity.component"; +import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; +import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; +import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; +import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; +import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; +import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; +import { DisplayUnitComponent } from "./view-components/display-unit/display-unit.component"; +import { MatOptionModule } from "@angular/material/core"; +import { MatSelectModule } from "@angular/material/select"; +import { ReactiveFormsModule } from "@angular/forms"; +import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; +import { MatIconModule } from "@angular/material/icon"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { EntitySelectModule } from "../entity-select/entity-select.module"; +import { MatInputModule } from "@angular/material/input"; +import { ViewModule } from "../../view/view.module"; +import { MatDatepickerModule } from "@angular/material/datepicker"; +import { MatCheckboxModule } from "@angular/material/checkbox"; + +@NgModule({ + declarations: [ + EditConfigurableEnumComponent, + EditTextComponent, + EditDateComponent, + EditSelectableComponent, + EditAgeComponent, + EditBooleanComponent, + EditLongTextComponent, + EditPhotoComponent, + EditEntityArrayComponent, + EditSingleEntityComponent, + EditPercentageComponent, + DisplayEntityComponent, + DisplayEntityArrayComponent, + DisplayTextComponent, + DisplayDateComponent, + DisplayConfigurableEnumComponent, + DisplayCheckmarkComponent, + ReadonlyFunctionComponent, + DisplayPercentageComponent, + DisplayUnitComponent, + ], + imports: [ + CommonModule, + MatOptionModule, + MatSelectModule, + ReactiveFormsModule, + ConfigurableEnumModule, + MatIconModule, + MatTooltipModule, + EntitySelectModule, + MatInputModule, + ViewModule, + MatDatepickerModule, + MatCheckboxModule, + ], + entryComponents: [ + EditConfigurableEnumComponent, + EditTextComponent, + EditDateComponent, + EditSelectableComponent, + EditAgeComponent, + EditBooleanComponent, + EditLongTextComponent, + EditPhotoComponent, + EditEntityArrayComponent, + EditSingleEntityComponent, + EditPercentageComponent, + DisplayEntityComponent, + DisplayEntityArrayComponent, + DisplayTextComponent, + DisplayDateComponent, + DisplayConfigurableEnumComponent, + DisplayCheckmarkComponent, + ReadonlyFunctionComponent, + DisplayPercentageComponent, + DisplayUnitComponent, + ], +}) +export class EntityUtilsModule {} diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-date/display-date.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.html rename to src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.scss b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.scss similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.scss rename to src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.scss diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts similarity index 96% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts index d676d11e88..b78b11f5e1 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.stories.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.stories.ts @@ -12,7 +12,7 @@ import { SchoolsModule } from "../../../../../child-dev-project/schools/schools. import { ChildrenModule } from "../../../../../child-dev-project/children/children.module"; import { DisplayEntityArrayComponent } from "./display-entity-array.component"; import { BehaviorSubject } from "rxjs"; -import { EntitySubrecordModule } from "../../entity-subrecord.module"; +import { EntitySubrecordModule } from "../../../entity-subrecord/entity-subrecord.module"; const child1 = new Child(); child1.name = "Test Name"; diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.html rename to src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.html diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.scss b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.scss similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.scss rename to src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.scss diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts similarity index 96% rename from src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts rename to src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts index d216813199..0ec4a2f297 100644 --- a/src/app/core/entity-components/entity-subrecord/view-components/display-entity/display-entity.stories.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.stories.ts @@ -14,7 +14,7 @@ import { RouterTestingModule } from "@angular/router/testing"; import { User } from "../../../../user/user"; import { SchoolsModule } from "../../../../../child-dev-project/schools/schools.module"; import { ChildrenModule } from "../../../../../child-dev-project/children/children.module"; -import { EntitySubrecordModule } from "../../entity-subrecord.module"; +import { EntitySubrecordModule } from "../../../entity-subrecord/entity-subrecord.module"; export default { title: "Core/EntityComponents/DisplayEntity", diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.html b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.html rename to src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.html diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.scss b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.scss similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.scss rename to src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.scss diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-percentage/display-percentage.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-text/display-text.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-text/display-text.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.html b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.html similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.html rename to src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.html diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.scss b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.scss similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.scss rename to src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.scss diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/display-unit/display-unit.component.ts rename to src/app/core/entity-components/entity-utils/view-components/display-unit/display-unit.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.html b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.html rename to src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html diff --git a/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.scss b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.scss similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.scss rename to src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.scss diff --git a/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.spec.ts rename to src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component.ts rename to src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts diff --git a/src/app/core/entity-components/entity-subrecord/view-components/view-component.ts b/src/app/core/entity-components/entity-utils/view-components/view-component.ts similarity index 100% rename from src/app/core/entity-components/entity-subrecord/view-components/view-component.ts rename to src/app/core/entity-components/entity-utils/view-components/view-component.ts diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index c5556ea6cf..e898db7a84 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -13,10 +13,10 @@ import { RecentAttendanceBlocksComponent } from "../../child-dev-project/childre import { ChildrenOverviewComponent } from "../../child-dev-project/schools/children-overview/children-overview.component"; import { ChildBlockComponent } from "../../child-dev-project/children/child-block/child-block.component"; import { FormComponent } from "../entity-components/entity-details/form/form.component"; -import { DisplayTextComponent } from "../entity-components/entity-subrecord/view-components/display-text/display-text.component"; -import { DisplayCheckmarkComponent } from "../entity-components/entity-subrecord/view-components/display-checkmark/display-checkmark.component"; -import { DisplayDateComponent } from "../entity-components/entity-subrecord/view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "../entity-components/entity-subrecord/view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayTextComponent } from "../entity-components/entity-utils/view-components/display-text/display-text.component"; +import { DisplayCheckmarkComponent } from "../entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component"; +import { DisplayDateComponent } from "../entity-components/entity-utils/view-components/display-date/display-date.component"; +import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; import { ActivityParticipantsSectionComponent } from "../../child-dev-project/attendance/activity-participants-section/activity-participants-section.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; @@ -24,23 +24,23 @@ import { ChildrenBmiDashboardComponent } from "../../child-dev-project/children/ import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/dashboard-shortcut-widget/dashboard-shortcut-widget.component"; import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; -import { EditTextComponent } from "../entity-components/entity-form/dynamic-form-components/edit-text/edit-text.component"; -import { EditConfigurableEnumComponent } from "../entity-components/entity-form/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; -import { EditDateComponent } from "../entity-components/entity-form/dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "../entity-components/entity-form/dynamic-form-components/edit-selectable/edit-selectable.component"; -import { EditAgeComponent } from "../entity-components/entity-form/dynamic-form-components/edit-age/edit-age.component"; -import { EditBooleanComponent } from "../entity-components/entity-form/dynamic-form-components/edit-boolean/edit-boolean.component"; -import { EditLongTextComponent } from "../entity-components/entity-form/dynamic-form-components/edit-long-text/edit-long-text.component"; -import { EditPhotoComponent } from "../entity-components/entity-form/dynamic-form-components/edit-photo/edit-photo.component"; -import { ReadonlyFunctionComponent } from "../entity-components/entity-subrecord/view-components/readonly-function/readonly-function.component"; -import { EditEntityArrayComponent } from "../entity-components/entity-form/dynamic-form-components/edit-entity-array/edit-entity-array.component"; +import { EditTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component"; +import { EditConfigurableEnumComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditDateComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component"; +import { EditSelectableComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component"; +import { EditAgeComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component"; +import { EditBooleanComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component"; +import { EditLongTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component"; +import { EditPhotoComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-photo/edit-photo.component"; +import { ReadonlyFunctionComponent } from "../entity-components/entity-utils/view-components/readonly-function/readonly-function.component"; +import { EditEntityArrayComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component"; import { SchoolBlockComponent } from "../../child-dev-project/schools/school-block/school-block.component"; -import { DisplayEntityComponent } from "../entity-components/entity-subrecord/view-components/display-entity/display-entity.component"; -import { EditSingleEntityComponent } from "../entity-components/entity-form/dynamic-form-components/edit-single-entity/edit-single-entity.component"; -import { DisplayEntityArrayComponent } from "../entity-components/entity-subrecord/view-components/display-entity-array/display-entity-array.component"; -import { EditPercentageComponent } from "../entity-components/entity-form/dynamic-form-components/edit-percentage/edit-percentage.component"; -import { DisplayPercentageComponent } from "../entity-components/entity-subrecord/view-components/display-percentage/display-percentage.component"; -import { DisplayUnitComponent } from "../entity-components/entity-subrecord/view-components/display-unit/display-unit.component"; +import { DisplayEntityComponent } from "../entity-components/entity-utils/view-components/display-entity/display-entity.component"; +import { EditSingleEntityComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component"; +import { DisplayEntityArrayComponent } from "../entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component"; +import { EditPercentageComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component"; +import { DisplayPercentageComponent } from "../entity-components/entity-utils/view-components/display-percentage/display-percentage.component"; +import { DisplayUnitComponent } from "../entity-components/entity-utils/view-components/display-unit/display-unit.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], From 6cbfce0497b8dd0670bf50d48df606e128d0a768 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 14:36:03 +0200 Subject: [PATCH 124/230] removed unused activity participants section --- ...tivity-participants-section.component.html | 46 ---------------- ...tivity-participants-section.component.scss | 0 ...ity-participants-section.component.spec.ts | 31 ----------- ...activity-participants-section.component.ts | 52 ------------------- .../attendance/attendance.module.ts | 2 - src/app/core/view/dynamic-components-map.ts | 2 - 6 files changed, 133 deletions(-) delete mode 100644 src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.html delete mode 100644 src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.scss delete mode 100644 src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.spec.ts delete mode 100644 src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.ts diff --git a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.html b/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.html deleted file mode 100644 index 988df55fb8..0000000000 --- a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.html +++ /dev/null @@ -1,46 +0,0 @@ -
- - - -
- -
- - - - - -
diff --git a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.scss b/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.spec.ts b/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.spec.ts deleted file mode 100644 index f1c813f751..0000000000 --- a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; -import { ActivityParticipantsSectionComponent } from "./activity-participants-section.component"; -import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; -import { AttendanceModule } from "../attendance.module"; -import { mockEntityMapper } from "app/core/entity/mock-entity-mapper-service"; - -describe("ActivityParticipantsSection", () => { - let component: ActivityParticipantsSectionComponent; - let fixture: ComponentFixture; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [AttendanceModule], - providers: [ - { provide: EntityMapperService, useValue: mockEntityMapper([]) }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(ActivityParticipantsSectionComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.ts b/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.ts deleted file mode 100644 index 9764e331a7..0000000000 --- a/src/app/child-dev-project/attendance/activity-participants-section/activity-participants-section.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, Input } from "@angular/core"; -import { RecurringActivity } from "../model/recurring-activity"; -import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; -import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; -import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { Child } from "../../children/model/child"; -import { EntityConstructor } from "../../../core/entity/entity"; -import { School } from "../../schools/model/school"; -import { User } from "../../../core/user/user"; - -@Component({ - selector: "app-activity-participants-section", - templateUrl: "./activity-participants-section.component.html", - styleUrls: ["./activity-participants-section.component.scss"], -}) -export class ActivityParticipantsSectionComponent - implements OnInitDynamicComponent { - @Input() entity: RecurringActivity; - - editing: boolean; - participants: string[] = []; - participatingGroups: string[] = []; - assignedUsers: string[] = []; - - readonly Child: EntityConstructor = Child; - readonly School: EntityConstructor = School; - readonly User: EntityConstructor = User; - - constructor(private entityMapper: EntityMapperService) {} - - onInitFromDynamicConfig(config: PanelConfig) { - this.entity = config.entity as RecurringActivity; - this.participants = this.entity.participants; - this.participatingGroups = this.entity.linkedGroups; - this.assignedUsers = this.entity.assignedTo; - } - - switchEdit() { - this.editing = !this.editing; - this.participants = [...this.entity.participants]; - this.participatingGroups = [...this.entity.linkedGroups]; - this.assignedUsers = [...this.entity.assignedTo]; - } - - async save() { - this.entity.participants = this.participants; - this.entity.linkedGroups = this.participatingGroups; - this.entity.assignedTo = this.assignedUsers; - await this.entityMapper.save(this.entity); - this.editing = false; - } -} diff --git a/src/app/child-dev-project/attendance/attendance.module.ts b/src/app/child-dev-project/attendance/attendance.module.ts index 7b19674f2d..7dfb391463 100644 --- a/src/app/child-dev-project/attendance/attendance.module.ts +++ b/src/app/child-dev-project/attendance/attendance.module.ts @@ -18,7 +18,6 @@ import { NgModule } from "@angular/core"; import { ActivityListComponent } from "./activity-list/activity-list.component"; import { EntityListModule } from "../../core/entity-components/entity-list/entity-list.module"; -import { ActivityParticipantsSectionComponent } from "./activity-participants-section/activity-participants-section.component"; import { ChildrenModule } from "../children/children.module"; import { MatButtonModule } from "@angular/material/button"; import { CommonModule } from "@angular/common"; @@ -62,7 +61,6 @@ import { EntitySelectModule } from "../../core/entity-components/entity-select/e @NgModule({ declarations: [ ActivityListComponent, - ActivityParticipantsSectionComponent, ActivityCardComponent, RollCallSetupComponent, AttendanceDayBlockComponent, diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index e898db7a84..66aca99ed5 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -17,7 +17,6 @@ import { DisplayTextComponent } from "../entity-components/entity-utils/view-com import { DisplayCheckmarkComponent } from "../entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component"; import { DisplayDateComponent } from "../entity-components/entity-utils/view-components/display-date/display-date.component"; import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; -import { ActivityParticipantsSectionComponent } from "../../child-dev-project/attendance/activity-participants-section/activity-participants-section.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "../../child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component"; @@ -51,7 +50,6 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["PreviousSchools", PreviousSchoolsComponent], ["Aser", AserComponent], ["GroupedChildAttendance", GroupedChildAttendanceComponent], - ["ActivityParticipantsSection", ActivityParticipantsSectionComponent], ["ActivityAttendanceSection", ActivityAttendanceSectionComponent], ["NotesOfChild", NotesOfChildComponent], ["HealthCheckup", HealthCheckupComponent], From 7ffe268a790a6a8220027496ca594fdbdef451fa Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:08:10 +0200 Subject: [PATCH 125/230] refactored entity select component --- .../attendance/attendance.module.ts | 4 +-- .../children/children.module.ts | 4 +-- .../child-dev-project/notes/notes.module.ts | 4 +-- .../entity-details/entity-details.module.ts | 6 ----- .../entity-details/form/form.component.ts | 2 +- .../entity-form/entity-form.module.ts | 8 ------ .../entity-select/entity-select.module.ts | 26 ------------------- .../entity-subrecord.module.ts | 2 -- .../entity-subrecord.component.spec.ts | 2 +- .../entity-subrecord.component.ts | 2 +- .../edit-entity-array.component.spec.ts | 10 ++++--- .../edit-single-entity.component.spec.ts | 6 ++--- .../entity-form.service.spec.ts | 0 .../entity-form.service.ts | 0 .../entity-select.component.html | 11 +++----- .../entity-select.component.scss | 0 .../entity-select.component.spec.ts | 0 .../entity-select/entity-select.component.ts | 0 .../entity-select/entity-select.stories.ts | 4 +-- .../entity-utils/entity-utils.module.ts | 9 +++++-- 20 files changed, 32 insertions(+), 68 deletions(-) delete mode 100644 src/app/core/entity-components/entity-form/entity-form.module.ts delete mode 100644 src/app/core/entity-components/entity-select/entity-select.module.ts rename src/app/core/entity-components/{entity-form => entity-utils}/entity-form.service.spec.ts (100%) rename src/app/core/entity-components/{entity-form => entity-utils}/entity-form.service.ts (100%) rename src/app/core/entity-components/{entity-select => entity-utils}/entity-select/entity-select.component.html (81%) rename src/app/core/entity-components/{entity-select => entity-utils}/entity-select/entity-select.component.scss (100%) rename src/app/core/entity-components/{entity-select => entity-utils}/entity-select/entity-select.component.spec.ts (100%) rename src/app/core/entity-components/{entity-select => entity-utils}/entity-select/entity-select.component.ts (100%) rename src/app/core/entity-components/{entity-select => entity-utils}/entity-select/entity-select.stories.ts (96%) diff --git a/src/app/child-dev-project/attendance/attendance.module.ts b/src/app/child-dev-project/attendance/attendance.module.ts index 7dfb391463..a24fe8261d 100644 --- a/src/app/child-dev-project/attendance/attendance.module.ts +++ b/src/app/child-dev-project/attendance/attendance.module.ts @@ -56,7 +56,7 @@ import { RouterModule } from "@angular/router"; import { Angulartics2Module } from "angulartics2"; import { MatSlideToggleModule } from "@angular/material/slide-toggle"; import { AttendanceManagerComponent } from "./attendance-manager/attendance-manager.component"; -import { EntitySelectModule } from "../../core/entity-components/entity-select/entity-select.module"; +import { EntityUtilsModule } from "../../core/entity-components/entity-utils/entity-utils.module"; @NgModule({ declarations: [ @@ -102,7 +102,7 @@ import { EntitySelectModule } from "../../core/entity-components/entity-select/e RouterModule, Angulartics2Module, MatSlideToggleModule, - EntitySelectModule, + EntityUtilsModule, ], exports: [ ActivityCardComponent, diff --git a/src/app/child-dev-project/children/children.module.ts b/src/app/child-dev-project/children/children.module.ts index db8d982402..115d4b5ce0 100644 --- a/src/app/child-dev-project/children/children.module.ts +++ b/src/app/child-dev-project/children/children.module.ts @@ -65,9 +65,9 @@ import { EntityListModule } from "../../core/entity-components/entity-list/entit import { WebdavModule } from "../../core/webdav/webdav.module"; import { BmiBlockComponent } from "./children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "./children-bmi-dashboard/children-bmi-dashboard.component"; -import { EntitySelectModule } from "../../core/entity-components/entity-select/entity-select.module"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; import { PhotoDatatype } from "./child-photo-service/datatype-photo"; +import { EntityUtilsModule } from "../../core/entity-components/entity-utils/entity-utils.module"; @NgModule({ imports: [ @@ -109,7 +109,7 @@ import { PhotoDatatype } from "./child-photo-service/datatype-photo"; ViewModule, EntitySubrecordModule, EntityListModule, - EntitySelectModule, + EntityUtilsModule, ], declarations: [ ChildBlockComponent, diff --git a/src/app/child-dev-project/notes/notes.module.ts b/src/app/child-dev-project/notes/notes.module.ts index ddb880082d..91915828a2 100644 --- a/src/app/child-dev-project/notes/notes.module.ts +++ b/src/app/child-dev-project/notes/notes.module.ts @@ -39,9 +39,9 @@ import { EntitySubrecordModule } from "../../core/entity-components/entity-subre import { EntityListModule } from "../../core/entity-components/entity-list/entity-list.module"; import { ConfigurableEnumModule } from "../../core/configurable-enum/configurable-enum.module"; import { AttendanceModule } from "../attendance/attendance.module"; -import { EntitySelectModule } from "../../core/entity-components/entity-select/entity-select.module"; import { MatSlideToggleModule } from "@angular/material/slide-toggle"; import { ChildMeetingNoteAttendanceComponent } from "./note-details/child-meeting-attendance/child-meeting-note-attendance.component"; +import { EntityUtilsModule } from "../../core/entity-components/entity-utils/entity-utils.module"; @NgModule({ declarations: [ @@ -93,8 +93,8 @@ import { ChildMeetingNoteAttendanceComponent } from "./note-details/child-meetin EntityListModule, ConfigurableEnumModule, AttendanceModule, - EntitySelectModule, MatSlideToggleModule, + EntityUtilsModule ], providers: [], }) diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 7682019ffb..771c0b47b0 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -4,12 +4,8 @@ import { EntityDetailsComponent } from "./entity-details.component"; import { FormComponent } from "./form/form.component"; import { ReactiveFormsModule } from "@angular/forms"; import { MatIconModule } from "@angular/material/icon"; -import { MatFormFieldModule } from "@angular/material/form-field"; import { MatTooltipModule } from "@angular/material/tooltip"; import { MatInputModule } from "@angular/material/input"; -import { MatCheckboxModule } from "@angular/material/checkbox"; -import { MatDatepickerModule } from "@angular/material/datepicker"; -import { MatSelectModule } from "@angular/material/select"; import { MatExpansionModule } from "@angular/material/expansion"; import { FlexLayoutModule } from "@angular/flex-layout"; import { MatButtonModule } from "@angular/material/button"; @@ -19,7 +15,6 @@ import { ViewModule } from "../../view/view.module"; import { EntityModule } from "../../entity/entity.module"; import { AlertsModule } from "../../alerts/alerts.module"; import { PermissionsModule } from "../../permissions/permissions.module"; -import { EntityFormModule } from "../entity-form/entity-form.module"; @NgModule({ declarations: [EntityDetailsComponent, FormComponent], @@ -37,7 +32,6 @@ import { EntityFormModule } from "../entity-form/entity-form.module"; EntityModule, AlertsModule, PermissionsModule, - EntityFormModule, MatTooltipModule, ], }) diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index adde478acc..e143949081 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -9,7 +9,7 @@ import { AlertService } from "../../../alerts/alert.service"; import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; import { getParentUrl } from "../../../../utils/utils"; import { OperationType } from "../../../permissions/entity-permissions.service"; -import { EntityFormService } from "../../entity-form/entity-form.service"; +import { EntityFormService } from "../../entity-utils/entity-form.service"; /** * This component creates a form based on the passed config. diff --git a/src/app/core/entity-components/entity-form/entity-form.module.ts b/src/app/core/entity-components/entity-form/entity-form.module.ts deleted file mode 100644 index a606d2f5c6..0000000000 --- a/src/app/core/entity-components/entity-form/entity-form.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; - -@NgModule({ - declarations: [], - imports: [CommonModule], -}) -export class EntityFormModule {} diff --git a/src/app/core/entity-components/entity-select/entity-select.module.ts b/src/app/core/entity-components/entity-select/entity-select.module.ts deleted file mode 100644 index 2e8220baa9..0000000000 --- a/src/app/core/entity-components/entity-select/entity-select.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { NgModule } from "@angular/core"; -import { CommonModule } from "@angular/common"; -import { EntitySelectComponent } from "./entity-select/entity-select.component"; -import { MatFormFieldModule } from "@angular/material/form-field"; -import { MatChipsModule } from "@angular/material/chips"; -import { ReactiveFormsModule } from "@angular/forms"; -import { MatAutocompleteModule } from "@angular/material/autocomplete"; -import { MatInputModule } from "@angular/material/input"; -import { MatTooltipModule } from "@angular/material/tooltip"; -import { ViewModule } from "../../view/view.module"; - -@NgModule({ - declarations: [EntitySelectComponent], - imports: [ - CommonModule, - MatFormFieldModule, - MatChipsModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatInputModule, - MatTooltipModule, - ViewModule, - ], - exports: [EntitySelectComponent], -}) -export class EntitySelectModule {} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 7cd79e91a5..8181309f28 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -13,7 +13,6 @@ import { MatButtonModule } from "@angular/material/button"; import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; -import { EntityFormModule } from "../entity-form/entity-form.module"; import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; @NgModule({ @@ -28,7 +27,6 @@ import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation MatSortModule, ViewModule, ReactiveFormsModule, - EntityFormModule, ConfirmationDialogModule, MatTooltipModule, MatButtonModule, diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 6f779378c6..06cd67d28f 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -25,7 +25,7 @@ import { AlertService } from "../../../alerts/alert.service"; import { PageEvent } from "@angular/material/paginator"; import { FormBuilder, FormGroup } from "@angular/forms"; import { Gender } from "../../../../child-dev-project/children/model/Gender"; -import { EntityFormService } from "../../entity-form/entity-form.service"; +import { EntityFormService } from "../../entity-utils/entity-form.service"; import { Subject } from "rxjs"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { MatSnackBar } from "@angular/material/snack-bar"; diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 47321d1057..92ec1df9e0 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -23,7 +23,7 @@ import { BehaviorSubject } from "rxjs"; import { entityListSortingAccessor } from "../../entity-list/sorting-accessor"; import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-details/form/FormConfig"; -import { EntityFormService } from "../../entity-form/entity-form.service"; +import { EntityFormService } from "../../entity-utils/entity-form.service"; export interface TableRow { record: T; diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts index f8085650fc..ab761f23d4 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.spec.ts @@ -1,11 +1,12 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { EditEntityArrayComponent } from "./edit-entity-array.component"; -import { EntitySelectModule } from "../../../entity-select/entity-select.module"; import { FormControl } from "@angular/forms"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { Child } from "../../../../../child-dev-project/children/model/child"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { EntityUtilsModule } from "../../entity-utils.module"; +import { EntitySchemaService } from "../../../../entity/schema/entity-schema.service"; describe("EditEntityArrayComponent", () => { let component: EditEntityArrayComponent; @@ -16,9 +17,12 @@ describe("EditEntityArrayComponent", () => { mockEntityMapper = jasmine.createSpyObj(["loadType"]); mockEntityMapper.loadType.and.resolveTo([]); await TestBed.configureTestingModule({ - imports: [EntitySelectModule, NoopAnimationsModule], + imports: [EntityUtilsModule, NoopAnimationsModule], declarations: [EditEntityArrayComponent], - providers: [{ provide: EntityMapperService, useValue: mockEntityMapper }], + providers: [ + { provide: EntityMapperService, useValue: mockEntityMapper }, + EntitySchemaService, + ], }).compileComponents(); }); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts index c947117aa5..280ca17407 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.spec.ts @@ -7,13 +7,13 @@ import { import { EditSingleEntityComponent } from "./edit-single-entity.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; -import { EntityFormModule } from "../../../entity-form/entity-form.module"; import { FormControl } from "@angular/forms"; import { EntitySchemaService } from "../../../../entity/schema/entity-schema.service"; -import { EntityFormService } from "../../../entity-form/entity-form.service"; +import { EntityFormService } from "../../entity-form.service"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { ChildSchoolRelation } from "../../../../../child-dev-project/children/model/childSchoolRelation"; import { School } from "../../../../../child-dev-project/schools/model/school"; +import { EntityUtilsModule } from "../../entity-utils.module"; describe("EditSingleEntityComponent", () => { let component: EditSingleEntityComponent; @@ -25,7 +25,7 @@ describe("EditSingleEntityComponent", () => { mockEntityMapper.loadType.and.resolveTo([]); await TestBed.configureTestingModule({ - imports: [EntityFormModule, NoopAnimationsModule], + imports: [EntityUtilsModule, NoopAnimationsModule], declarations: [EditSingleEntityComponent], providers: [ EntitySchemaService, diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-utils/entity-form.service.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-form/entity-form.service.spec.ts rename to src/app/core/entity-components/entity-utils/entity-form.service.spec.ts diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-utils/entity-form.service.ts similarity index 100% rename from src/app/core/entity-components/entity-form/entity-form.service.ts rename to src/app/core/entity-components/entity-utils/entity-form.service.ts diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html similarity index 81% rename from src/app/core/entity-components/entity-select/entity-select/entity-select.component.html rename to src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html index 6fcccfffbd..42d4415539 100644 --- a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.html +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html @@ -19,11 +19,9 @@ [selectable]="selectable && formControl.enabled" [removable]="removable && formControl.enabled" *ngFor="let entity of selection_" - class="chip"> -

{{entity["name"]}}

- - - + class="chip" + > +
-

{{res["name"]}}

- +
diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.scss b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.scss similarity index 100% rename from src/app/core/entity-components/entity-select/entity-select/entity-select.component.scss rename to src/app/core/entity-components/entity-utils/entity-select/entity-select.component.scss diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.spec.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-select/entity-select/entity-select.component.spec.ts rename to src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.component.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts similarity index 100% rename from src/app/core/entity-components/entity-select/entity-select/entity-select.component.ts rename to src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts diff --git a/src/app/core/entity-components/entity-select/entity-select/entity-select.stories.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.stories.ts similarity index 96% rename from src/app/core/entity-components/entity-select/entity-select/entity-select.stories.ts rename to src/app/core/entity-components/entity-utils/entity-select/entity-select.stories.ts index 9c75eea5c9..30a6067e08 100644 --- a/src/app/core/entity-components/entity-select/entity-select/entity-select.stories.ts +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.stories.ts @@ -9,9 +9,9 @@ import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { ChildrenService } from "../../../../child-dev-project/children/children.service"; import { BehaviorSubject } from "rxjs"; import { RouterTestingModule } from "@angular/router/testing"; -import { EntitySelectModule } from "../entity-select.module"; import { EntitySelectComponent } from "./entity-select.component"; import { ChildrenModule } from "../../../../child-dev-project/children/children.module"; +import { EntityUtilsModule } from "../entity-utils.module"; const child1 = new Child(); child1.name = "First Child"; @@ -41,7 +41,7 @@ export default { decorators: [ moduleMetadata({ imports: [ - EntitySelectModule, + EntityUtilsModule, NoopAnimationsModule, RouterTestingModule, ChildrenModule, diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index dbad06741b..8fb6e2a2de 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -26,11 +26,13 @@ import { ReactiveFormsModule } from "@angular/forms"; import { ConfigurableEnumModule } from "../../configurable-enum/configurable-enum.module"; import { MatIconModule } from "@angular/material/icon"; import { MatTooltipModule } from "@angular/material/tooltip"; -import { EntitySelectModule } from "../entity-select/entity-select.module"; import { MatInputModule } from "@angular/material/input"; import { ViewModule } from "../../view/view.module"; import { MatDatepickerModule } from "@angular/material/datepicker"; import { MatCheckboxModule } from "@angular/material/checkbox"; +import { EntitySelectComponent } from "./entity-select/entity-select.component"; +import { MatAutocompleteModule } from "@angular/material/autocomplete"; +import { MatChipsModule } from "@angular/material/chips"; @NgModule({ declarations: [ @@ -54,6 +56,7 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; ReadonlyFunctionComponent, DisplayPercentageComponent, DisplayUnitComponent, + EntitySelectComponent, ], imports: [ CommonModule, @@ -63,11 +66,12 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; ConfigurableEnumModule, MatIconModule, MatTooltipModule, - EntitySelectModule, MatInputModule, ViewModule, MatDatepickerModule, MatCheckboxModule, + MatAutocompleteModule, + MatChipsModule, ], entryComponents: [ EditConfigurableEnumComponent, @@ -91,5 +95,6 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; DisplayPercentageComponent, DisplayUnitComponent, ], + exports: [DisplayEntityComponent, EntitySelectComponent], }) export class EntityUtilsModule {} From e8743c9e05fc1909866fd3d37354303eb538018f Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:27:36 +0200 Subject: [PATCH 126/230] changed default date format --- .../activity-attendance-section.component.ts | 2 +- .../view-components/display-date/display-date.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts index 4b5fee4a88..3f9e18e451 100644 --- a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts +++ b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts @@ -29,7 +29,7 @@ export class ActivityAttendanceSectionComponent id: "periodFrom", placeholder: "Month", view: "DisplayDate", - additional: "MM/YYYY", + additional: "YYYY-MM", }, { id: "presentEvents", diff --git a/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts index 693f2a3279..63af04b870 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-date/display-date.component.ts @@ -10,7 +10,7 @@ import { ViewComponent } from "../view-component"; template: `{{ entity[property] | date: format }}`, }) export class DisplayDateComponent extends ViewComponent { - format = "shortDate"; + format = "YYYY-MM-dd"; onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); From b78f24d9c4e702c4177af9b94ddca1a654b4aceb Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:29:49 +0200 Subject: [PATCH 127/230] added visible from attribute --- .../educational-material.component.ts | 8 ++++---- .../notes-of-child/notes-of-child.component.ts | 10 +++++----- .../entity-details/form/FormConfig.ts | 2 ++ .../entity-subrecord/entity-subrecord.component.ts | 13 ++++--------- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index e38742d28c..71f85858f0 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -20,10 +20,10 @@ export class EducationalMaterialComponent materialTypes = EducationalMaterial.MATERIAL_ALL; columns: FormFieldConfig[] = [ - { id: "date" }, - { id: "materialType" }, - { id: "materialAmount" }, - { id: "description" }, + { id: "date", visibleFrom: "xs" }, + { id: "materialType", visibleFrom: "xs" }, + { id: "materialAmount", visibleFrom: "md" }, + { id: "description", visibleFrom: "md" }, ]; constructor(private childrenService: ChildrenService) {} diff --git a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts index 9c24ba33f1..d43ce2a209 100644 --- a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts +++ b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts @@ -26,11 +26,11 @@ export class NotesOfChildComponent records: Array = []; columns: FormFieldConfig[] = [ - { id: "date" }, - { id: "subject" }, - { id: "text" }, - { id: "authors" }, - { id: "warningLevel" }, + { id: "date", visibleFrom: "xs" }, + { id: "subject", visibleFrom: "xs" }, + { id: "text", visibleFrom: "md" }, + { id: "authors", visibleFrom: "md" }, + { id: "warningLevel", visibleFrom: "md" }, ]; constructor( diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-details/form/FormConfig.ts index 1ccc2d0a64..379da1ad39 100644 --- a/src/app/core/entity-components/entity-details/form/FormConfig.ts +++ b/src/app/core/entity-components/entity-details/form/FormConfig.ts @@ -30,4 +30,6 @@ export interface FormFieldConfig { noSorting?: boolean; additional?: any; + + visibleFrom?: string; } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 92ec1df9e0..57713bc087 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -323,14 +323,9 @@ export class EntitySubrecordComponent */ setupTable() { if (this.columns !== undefined && this.screenWidth !== "") { - const columnsHelpArray = []; - const entitySubrecordComponent = this; - this.columns.forEach(function (this, col) { - if (entitySubrecordComponent.isVisible(col)) { - columnsHelpArray.push(col.id); - } - }); - this.columnsToDisplay = columnsHelpArray; + this.columnsToDisplay = this.columns + .filter((col) => this.isVisible(col)) + .map((col) => col.id); if (this.screenWidth !== "xs") { this.columnsToDisplay.push("actions"); } @@ -343,7 +338,7 @@ export class EntitySubrecordComponent * @param col column that is checked * @return returns true if column is visible */ - private isVisible(col) { + private isVisible(col: FormFieldConfig) { let returnVal; switch (col.visibleFrom) { case "xl": { From a3fc40c727ef18216368a30a4c6774da7d2707bd Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:30:15 +0200 Subject: [PATCH 128/230] added visible from attribute --- .../entity-subrecord/entity-subrecord.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 57713bc087..0d55a9be80 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -338,7 +338,7 @@ export class EntitySubrecordComponent * @param col column that is checked * @return returns true if column is visible */ - private isVisible(col: FormFieldConfig) { + private isVisible(col: FormFieldConfig): boolean { let returnVal; switch (col.visibleFrom) { case "xl": { From 892fe585c169f36706ea8194f0390f5ab8273c1c Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:40:05 +0200 Subject: [PATCH 129/230] removed unused code --- .../entity-list/entity-list.component.spec.ts | 7 +------ .../entity-components/entity-list/entity-list.component.ts | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 05670e91ef..ac6b4788f0 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -1,8 +1,4 @@ -import { - ComponentFixture, - TestBed, - waitForAsync, -} from "@angular/core/testing"; +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { EntityListComponent } from "./entity-list.component"; import { CommonModule, DatePipe } from "@angular/common"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; @@ -157,7 +153,6 @@ describe("EntityListComponent", () => { }); it("should set the clicked column group", () => { - component.ready = true; const clickedColumnGroup = testConfig.columnGroups.groups[0]; component.columnGroupClick(clickedColumnGroup.name); expect(component.selectedColumnGroup).toEqual(clickedColumnGroup.name); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 77deee85de..ac045ad74a 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -57,12 +57,10 @@ export class EntityListComponent operationType = OperationType; - ready = true; columnsToDisplay: string[] = []; selectedColumnGroup: string = ""; filterSelections: FilterComponentSettings[] = []; - filterString = ""; constructor( From 3ee1a211aaeba29111b53742e3e8df445743b61f Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 26 May 2021 15:50:14 +0200 Subject: [PATCH 130/230] fixed prettier errors --- .../children/children.service.ts | 4 +--- .../child-dev-project/notes/notes.module.ts | 2 +- .../filter-generator.service.spec.ts | 8 +++---- .../edit-percentage.component.spec.ts | 21 ++++++++++--------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/app/child-dev-project/children/children.service.ts b/src/app/child-dev-project/children/children.service.ts index 1b0104f799..f89802e363 100644 --- a/src/app/child-dev-project/children/children.service.ts +++ b/src/app/child-dev-project/children/children.service.ts @@ -462,9 +462,7 @@ export class ChildrenService { }; } - async getSchoolRelationsFor( - childId: string - ): Promise { + async getSchoolRelationsFor(childId: string): Promise { return await this.querySortedRelations(childId); } } diff --git a/src/app/child-dev-project/notes/notes.module.ts b/src/app/child-dev-project/notes/notes.module.ts index 91915828a2..34c77dfb2f 100644 --- a/src/app/child-dev-project/notes/notes.module.ts +++ b/src/app/child-dev-project/notes/notes.module.ts @@ -94,7 +94,7 @@ import { EntityUtilsModule } from "../../core/entity-components/entity-utils/ent ConfigurableEnumModule, AttendanceModule, MatSlideToggleModule, - EntityUtilsModule + EntityUtilsModule, ], providers: [], }) diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts index 101dd9c4ec..121b160056 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts @@ -182,16 +182,14 @@ describe("FilterGeneratorService", () => { const yesterdayNote = new Note(); const notes = [todayNote, yesterdayNote]; yesterdayNote.date = moment().subtract(1, "day").toDate(); - const allFilter = filter.filterSettings.options.find( - (filter) => filter.key === "" - ); + const allFilter = filter.filterSettings.options.find((f) => f.key === ""); expect(notes.filter(allFilter.filterFun)).toEqual(notes); const todayFilter = filter.filterSettings.options.find( - (filter) => filter.key === "today" + (f) => f.key === "today" ); expect(notes.filter(todayFilter.filterFun)).toEqual([todayNote]); const beforeFilter = filter.filterSettings.options.find( - (filter) => filter.key === "before" + (f) => f.key === "before" ); expect(notes.filter(beforeFilter.filterFun)).toEqual([yesterdayNote]); }); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts index 6d023ad581..82d65a076b 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.spec.ts @@ -14,6 +14,7 @@ import { NoopAnimationsModule } from "@angular/platform-browser/animations"; describe("EditPercentageComponent", () => { let component: EditPercentageComponent; let fixture: ComponentFixture; + let formGroup: FormGroup; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -31,7 +32,7 @@ describe("EditPercentageComponent", () => { fixture = TestBed.createComponent(EditPercentageComponent); component = fixture.componentInstance; const formControl = new FormControl(); - new FormGroup({ testProperty: formControl }); + formGroup = new FormGroup({ testProperty: formControl }); component.onInitFromDynamicConfig({ formControl: formControl, propertySchema: {}, @@ -46,30 +47,30 @@ describe("EditPercentageComponent", () => { it("should only allow valid percentage values", () => { component.formControl.setValue(101); - expect(component.formControl.invalid).toBeTrue(); + expect(formGroup.invalid).toBeTrue(); component.formControl.setValue(100); - expect(component.formControl.valid).toBeTrue(); + expect(formGroup.valid).toBeTrue(); component.formControl.setValue(10); - expect(component.formControl.valid).toBeTrue(); + expect(formGroup.valid).toBeTrue(); component.formControl.setValue(0); - expect(component.formControl.valid).toBeTrue(); + expect(formGroup.valid).toBeTrue(); component.formControl.setValue(-1); - expect(component.formControl.invalid).toBeTrue(); + expect(formGroup.invalid).toBeTrue(); component.formControl.setValue("one" as any); - expect(component.formControl.invalid).toBeTrue(); + expect(formGroup.invalid).toBeTrue(); }); it("should keep existing validators", () => { component.formControl.setValue(null); - expect(component.formControl.valid).toBeTrue(); + expect(formGroup.valid).toBeTrue(); const control = new FormControl(0, [Validators.required]); - new FormGroup({ testProperty: control }); + formGroup.setControl("testProperty", control); component.onInitFromDynamicConfig({ formControl: control, propertySchema: {}, @@ -77,6 +78,6 @@ describe("EditPercentageComponent", () => { }); component.formControl.setValue(null); - expect(component.formControl.invalid).toBeTrue(); + expect(formGroup.invalid).toBeTrue(); }); }); From e2e2110d9f7f9f1e89eb8b48c7f5c157c1ebfb87 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 31 May 2021 08:20:52 +0200 Subject: [PATCH 131/230] removed unused method --- .../entity-subrecord/entity-subrecord.component.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 0d55a9be80..b664a0bcee 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -1,5 +1,4 @@ import { - AfterViewInit, Component, EventEmitter, Input, @@ -49,8 +48,7 @@ export interface TableRow { templateUrl: "./entity-subrecord.component.html", styleUrls: ["./entity-subrecord.component.scss"], }) -export class EntitySubrecordComponent - implements OnChanges, AfterViewInit { +export class EntitySubrecordComponent implements OnChanges { /** * Global state of pagination size for all entity subrecord components. * @@ -143,8 +141,6 @@ export class EntitySubrecordComponent } } - ngAfterViewInit() {} - private initDefaultSort() { this.recordsDataSource.sort = this.sort; this.recordsDataSource.paginator = this.paginator; From c6b743fd3119b9f279edb243da8a1a59f4955089 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 31 May 2021 09:21:10 +0200 Subject: [PATCH 132/230] added visible from info to aser component --- .../aser/aser-component/aser.component.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/child-dev-project/aser/aser-component/aser.component.ts b/src/app/child-dev-project/aser/aser-component/aser.component.ts index be1402ee2e..f1053985df 100644 --- a/src/app/child-dev-project/aser/aser-component/aser.component.ts +++ b/src/app/child-dev-project/aser/aser-component/aser.component.ts @@ -21,12 +21,12 @@ export class AserComponent implements OnChanges, OnInitDynamicComponent { records: Array = []; columns: FormFieldConfig[] = [ - { id: "date" }, - { id: "math" }, - { id: "english" }, - { id: "hindi" }, - { id: "bengali" }, - { id: "remarks" }, + { id: "date", visibleFrom: "xs" }, + { id: "math", visibleFrom: "xs" }, + { id: "english", visibleFrom: "xs" }, + { id: "hindi", visibleFrom: "md" }, + { id: "bengali", visibleFrom: "md" }, + { id: "remarks", visibleFrom: "md" }, ]; constructor(private childrenService: ChildrenService) {} From a9a97ed5cb396d636416ec1b40b113d223827411 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 31 May 2021 09:24:42 +0200 Subject: [PATCH 133/230] added hover effect to table rows --- .../entity-list/entity-list.component.scss | 9 --------- .../entity-subrecord/entity-subrecord.component.html | 1 + .../entity-subrecord/entity-subrecord.component.scss | 4 ++++ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.scss b/src/app/core/entity-components/entity-list/entity-list.component.scss index b1a8e87d33..3651ee5d4a 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.scss +++ b/src/app/core/entity-components/entity-list/entity-list.component.scss @@ -15,10 +15,6 @@ padding-left: 8px; } -.table-list-item:hover { - background: #f5f5f5; -} - .button-icon { font-size: 1.5em; margin-right: 5px; @@ -27,8 +23,3 @@ .align-form-field { padding-bottom: 1.25em; } - -.cell-with-blocks { - white-space: nowrap; - overflow: hidden; -} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index a42d44e905..c6606fe3e6 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -117,6 +117,7 @@ [ngStyle]=" getBackgroundColor && { 'background-color': getBackgroundColor(row.record) } " + class="table-row" > Date: Mon, 31 May 2021 09:39:49 +0200 Subject: [PATCH 134/230] made is visible form function more compact --- .../entity-subrecord.component.ts | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index b664a0bcee..fa1ed310e2 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -335,28 +335,13 @@ export class EntitySubrecordComponent implements OnChanges { * @return returns true if column is visible */ private isVisible(col: FormFieldConfig): boolean { - let returnVal; - switch (col.visibleFrom) { - case "xl": { - returnVal = this.screenWidth.match("xl"); - break; - } - case "lg": { - returnVal = this.screenWidth.match("(lg|xl)"); - break; - } - case "md": { - returnVal = this.screenWidth.match("(md|lg|xl)"); - break; - } - case "sm": { - returnVal = this.screenWidth.match("(sm|md|lg|xl)"); - break; - } - default: { - returnVal = true; - } + const visibilityGroups = ["sm", "md", "lg", "xl"]; + const visibleFromIndex = visibilityGroups.indexOf(col.visibleFrom); + if (visibleFromIndex !== -1) { + const regex = visibilityGroups.slice(visibleFromIndex).join("|"); + return !!this.screenWidth.match(regex); + } else { + return true; } - return returnVal; } } From 74c76d94e7b5eaf6d1e55bddc742ba59ffc1e9ec Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 31 May 2021 09:56:11 +0200 Subject: [PATCH 135/230] fixed wrong columns being displayed --- .../entity-subrecord/entity-subrecord.component.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index fa1ed310e2..cdf69c07ec 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -17,8 +17,7 @@ import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { Entity } from "../../../entity/entity"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { AlertService } from "../../../alerts/alert.service"; -import { DatePipe } from "@angular/common"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, Subscription } from "rxjs"; import { entityListSortingAccessor } from "../../entity-list/sorting-accessor"; import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-details/form/FormConfig"; @@ -79,6 +78,7 @@ export class EntitySubrecordComponent implements OnChanges { /** data displayed in the template's table */ recordsDataSource = new MatTableDataSource>(); + private mediaSubscription: Subscription; private screenWidth = ""; @ViewChild(MatSort) sort: MatSort; @@ -90,11 +90,10 @@ export class EntitySubrecordComponent implements OnChanges { private _snackBar: MatSnackBar, private _confirmationDialog: ConfirmationDialogService, private alertService: AlertService, - private datePipe: DatePipe, private media: MediaObserver, private entityFormService: EntityFormService ) { - this.media + this.mediaSubscription = this.media .asObservable() .pipe(untilDestroyed(this)) .subscribe((change: MediaChange[]) => { @@ -120,6 +119,9 @@ export class EntitySubrecordComponent implements OnChanges { this.initFormGroups(); this.initDefaultSort(); } + if (changes.hasOwnProperty("columnsToDisplay")) { + this.mediaSubscription.unsubscribe(); + } } private initFormGroups() { From 7e5f97f95a395e0a0ac3c95d07b115a8a9b346de Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 31 May 2021 11:41:34 +0200 Subject: [PATCH 136/230] removed unused files --- .../column-description-input-type.enum.ts | 16 ----- .../entity-subrecord/column-description.ts | 71 ------------------- .../form-validation-result.ts | 10 --- 3 files changed, 97 deletions(-) delete mode 100644 src/app/core/entity-components/entity-subrecord/column-description-input-type.enum.ts delete mode 100644 src/app/core/entity-components/entity-subrecord/column-description.ts delete mode 100644 src/app/core/entity-components/entity-subrecord/form-validation-result.ts diff --git a/src/app/core/entity-components/entity-subrecord/column-description-input-type.enum.ts b/src/app/core/entity-components/entity-subrecord/column-description-input-type.enum.ts deleted file mode 100644 index 1abbca16dc..0000000000 --- a/src/app/core/entity-components/entity-subrecord/column-description-input-type.enum.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Input types available for columns generated by the {@link EntitySubrecordComponent}. - * Defines what form field is offered to the user to edit the column's value. - */ -export enum ColumnDescriptionInputType { - TEXT = "text", - NUMBER = "number", - DATE = "date", - MONTH = "month", - TEXTAREA = "textarea", - SELECT = "select", - AUTOCOMPLETE = "autocomplete", - FUNCTION = "function", - READONLY = "readonly", - CONFIGURABLE_ENUM = "configurable_enum", -} diff --git a/src/app/core/entity-components/entity-subrecord/column-description.ts b/src/app/core/entity-components/entity-subrecord/column-description.ts deleted file mode 100644 index eda7e21748..0000000000 --- a/src/app/core/entity-components/entity-subrecord/column-description.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of ndb-core. - * - * ndb-core is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ndb-core is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ndb-core. If not, see . - */ - -import { ColumnDescriptionInputType } from "./column-description-input-type.enum"; -import { Entity } from "../../entity/entity"; - -/** - * A ColumnDescription describes a single column to be generated in the generic {@link EntitySubrecordComponent}. - * . - */ -export interface ColumnDescription { - /** - * The identifier of the column and key of the entities' property that is displayed in that column - */ - name: string; - - /** The label for the column displayed in the table header */ - label: string; - - /** How the value of this column is displayed and what kind of form field is provided to edit it */ - inputType: ColumnDescriptionInputType; - - component?: string; - - /** Array of possible values for editing this column; required for inputTypes select and autocomplete */ - selectValues?: Array<{ value: any; label: string }>; - - /** - * visibleFrom The minimal screen size the column is shown. - * screen size classes: xs 'screen and (max-width: 599px)' - * sm 'screen and (min-width: 600px) and (max-width: 959px)' - * md 'screen and (min-width: 960px) and (max-width: 1279px)' - * lg 'screen and (min-width: 1280px) and (max-width: 1919px)' - * xl 'screen and (min-width: 1920px) and (max-width: 5000px)' - */ - visibleFrom?: string; - - /** (Optional) function building a ngStyle value, receiving the value as a parameter */ - styleBuilder?: (value) => Object; - - /** - * a function taking the full object (Entity instance) and returning the value that is displayed in this column. - * - * use this function to format a value or calculate a more complex value that is not directly a property of the entity object. - */ - valueFunction?: (entity: Entity) => any; - - /** - * A string that will be displayed as a tooltip when hovering the column title - */ - tooltip?: string; - - /** - * In case `inputType === ColumnDescriptionInputType.CONFIGURABLE_ENUM` this required to be set to the id of the enum - */ - enumId?: string; -} diff --git a/src/app/core/entity-components/entity-subrecord/form-validation-result.ts b/src/app/core/entity-components/entity-subrecord/form-validation-result.ts deleted file mode 100644 index 7ac4b26423..0000000000 --- a/src/app/core/entity-components/entity-subrecord/form-validation-result.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Overall result of a form validation in an {@link EntitySubrecordComponent}. - */ -export interface FormValidationResult { - /** whether validation has succeeded without errors */ - hasPassedValidation: boolean; - - /** message displayed to explain validation problems */ - validationMessage: string; -} From 58c9ecb15dada15783ca8db5e77a96b1ceb46a5d Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 1 Jun 2021 09:31:03 +0200 Subject: [PATCH 137/230] automatically opening a popup when clicking a form --- .../entity-details/entity-details.module.ts | 1 + .../entity-details/form/FormConfig.ts | 4 ---- .../entity-details/form/form.component.ts | 12 +++--------- .../entity-subrecord/entity-subrecord.module.ts | 2 ++ .../entity-subrecord.component.ts | 16 +++++++++++++++- .../entity-subrecord/entity-subrecord.stories.ts | 5 +++++ .../entity-utils/entity-form.service.ts | 2 ++ 7 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 771c0b47b0..55a73f1f41 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -34,5 +34,6 @@ import { PermissionsModule } from "../../permissions/permissions.module"; PermissionsModule, MatTooltipModule, ], + entryComponents: [FormComponent], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-details/form/FormConfig.ts index 379da1ad39..3ab500df7d 100644 --- a/src/app/core/entity-components/entity-details/form/FormConfig.ts +++ b/src/app/core/entity-components/entity-details/form/FormConfig.ts @@ -1,7 +1,3 @@ -export interface FormConfig { - cols: FormFieldConfig[][]; -} - export interface FormFieldConfig { view?: string; diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index e143949081..de0bf2d7c1 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { FormGroup } from "@angular/forms"; import { Router } from "@angular/router"; -import { FormConfig, FormFieldConfig } from "./FormConfig"; +import { FormFieldConfig } from "./FormConfig"; import { PanelConfig } from "../EntityDetailsConfig"; import { Entity } from "../../../entity/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; @@ -26,7 +26,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { operationType = OperationType; creatingNew = false; - config: FormConfig; columns: FormFieldConfig[][]; form: FormGroup; @@ -39,7 +38,7 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { ) {} ngOnInit() { - this.initForm(); + this.buildFormConfig(); if (this.creatingNew) { this.switchEdit(); } @@ -47,7 +46,7 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { onInitFromDynamicConfig(config: PanelConfig) { this.entity = config.entity; - this.config = config.config; + this.columns = config.config?.cols; if (config.creatingNew) { this.creatingNew = true; } @@ -74,11 +73,6 @@ export class FormComponent implements OnInitDynamicComponent, OnInit { this.buildFormConfig(); } - private initForm(): void { - this.columns = this.config.cols; - this.buildFormConfig(); - } - private buildFormConfig() { const flattenedFormFields = new Array().concat( ...this.columns diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 8181309f28..e5dbcc232d 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -14,6 +14,7 @@ import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; +import { EntityDetailsModule } from "../entity-details/entity-details.module"; @NgModule({ declarations: [EntitySubrecordComponent, KeysPipe], @@ -31,6 +32,7 @@ import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation MatTooltipModule, MatButtonModule, MatIconModule, + EntityDetailsModule, ], exports: [EntitySubrecordComponent, KeysPipe], }) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index cdf69c07ec..8acc0dbd31 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -22,6 +22,8 @@ import { entityListSortingAccessor } from "../../entity-list/sorting-accessor"; import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-details/form/FormConfig"; import { EntityFormService } from "../../entity-utils/entity-form.service"; +import { MatDialog } from "@angular/material/dialog"; +import { FormComponent } from "../../entity-details/form/form.component"; export interface TableRow { record: T; @@ -91,7 +93,8 @@ export class EntitySubrecordComponent implements OnChanges { private _confirmationDialog: ConfirmationDialogService, private alertService: AlertService, private media: MediaObserver, - private entityFormService: EntityFormService + private entityFormService: EntityFormService, + private dialog: MatDialog ) { this.mediaSubscription = this.media .asObservable() @@ -313,6 +316,17 @@ export class EntitySubrecordComponent implements OnChanges { showRecord(row: TableRow) { if (!row.formGroup || row.formGroup.disabled) { this.rowClicked.emit(row.record); + const dialogRef = this.dialog.open(FormComponent, { + width: "80%", + }); + const columnsCopy = []; + this.columns.forEach((col) => { + const newCol = {}; + Object.assign(newCol, col); + columnsCopy.push([newCol]); + }); + dialogRef.componentInstance.columns = columnsCopy; + dialogRef.componentInstance.entity = row.record; } } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts index da9a4c1e37..c0cfed5f6b 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.stories.ts @@ -19,6 +19,7 @@ import { ChildrenModule } from "../../../../child-dev-project/children/children. import { ChildrenService } from "../../../../child-dev-project/children/children.service"; import { of } from "rxjs"; import * as faker from "faker"; +import { EntityPermissionsService } from "../../../permissions/entity-permissions.service"; const configService = new ConfigService(); const schemaService = new EntitySchemaService(); @@ -70,6 +71,10 @@ export default { of(faker.random.arrayElement(childGenerator.entities)), }, }, + { + provide: EntityPermissionsService, + useValue: { userIsPermitted: () => true }, + }, ], }), ], diff --git a/src/app/core/entity-components/entity-utils/entity-form.service.ts b/src/app/core/entity-components/entity-utils/entity-form.service.ts index e32fab88d3..879c870d46 100644 --- a/src/app/core/entity-components/entity-utils/entity-form.service.ts +++ b/src/app/core/entity-components/entity-utils/entity-form.service.ts @@ -45,6 +45,8 @@ export class EntityFormService { formField.forTable = true; formField.placeholder = propertySchema?.labelShort || formField.placeholder; + } else { + formField.forTable = false; } } From d7f392b61dbca10c12f7b060d3e565e26da4911d Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 1 Jun 2021 10:10:08 +0200 Subject: [PATCH 138/230] unsing popup as default with possible overwrite for entity subrecord --- ...activity-attendance-section.component.html | 2 +- .../attendance-details.component.html | 2 +- .../notes-of-child.component.html | 2 +- .../children-overview.component.ts | 4 +- .../entity-list/entity-list.component.html | 2 +- .../entity-list/entity-list.module.ts | 2 + .../entity-subrecord.component.html | 2 +- .../entity-subrecord.component.spec.ts | 6 +-- .../entity-subrecord.component.ts | 38 +++++++------- .../historical-data/historical-data.module.ts | 3 +- .../historical-data.stories.ts | 50 +++++++++++-------- 11 files changed, 62 insertions(+), 51 deletions(-) diff --git a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.html b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.html index 6d0c9f46eb..c81b0fa847 100644 --- a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.html +++ b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.html @@ -7,7 +7,7 @@ diff --git a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.html b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.html index caecc86c6f..2a3fd6911b 100644 --- a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.html +++ b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.html @@ -93,7 +93,7 @@

diff --git a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.html b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.html index b77b9eda51..8155ac94b1 100644 --- a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.html +++ b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.html @@ -2,7 +2,7 @@ [records]="records" [columns]="columns" [newRecordFactory]="generateNewRecordFactory()" - (rowClicked)="showNoteDetails($event)" + [showEntity]="showNoteDetails.bind(this)" [getBackgroundColor]="getColor" > diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts index c5169d23e3..1fb8010d88 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts @@ -11,10 +11,10 @@ import { Router } from "@angular/router"; */ @Component({ selector: "app-children-overview", - template: ``, }) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.html b/src/app/core/entity-components/entity-list/entity-list.component.html index 00e8808b31..38aa67e5b3 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.html +++ b/src/app/core/entity-components/entity-list/entity-list.component.html @@ -110,7 +110,7 @@

{{ listName }}

[records]="filteredEntities" [columns]="columns" [editable]="false" - (rowClicked)="elementClick.emit($event)" + [showEntity]="elementClick.emit.bind(elementClick)" [columnsToDisplay]="columnsToDisplay" >
diff --git a/src/app/core/entity-components/entity-list/entity-list.module.ts b/src/app/core/entity-components/entity-list/entity-list.module.ts index 2906116611..6eb82a368b 100644 --- a/src/app/core/entity-components/entity-list/entity-list.module.ts +++ b/src/app/core/entity-components/entity-list/entity-list.module.ts @@ -19,6 +19,7 @@ import { ViewModule } from "../../view/view.module"; import { ListFilterComponent } from "./list-filter/list-filter.component"; import { PermissionsModule } from "../../permissions/permissions.module"; import { EntitySubrecordModule } from "../entity-subrecord/entity-subrecord.module"; +import { EntityUtilsModule } from "../entity-utils/entity-utils.module"; @NgModule({ declarations: [ListFilterComponent, EntityListComponent], @@ -42,6 +43,7 @@ import { EntitySubrecordModule } from "../entity-subrecord/entity-subrecord.modu MatPaginatorModule, PermissionsModule, EntitySubrecordModule, + EntityUtilsModule, ], exports: [EntityListComponent], entryComponents: [], diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index c6606fe3e6..05268483cd 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -19,7 +19,7 @@ { it("should notify when an entity is clicked", (done) => { const child = new Child(); - component.rowClicked.subscribe((entity) => { + component.showEntity = (entity) => { expect(entity).toEqual(child); done(); - }); + }; - component.showRecord({ record: child }); + component.rowClick({ record: child }); }); }); diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 8acc0dbd31..b126a06be7 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -1,9 +1,7 @@ import { Component, - EventEmitter, Input, OnChanges, - Output, SimpleChanges, ViewChild, } from "@angular/core"; @@ -75,7 +73,8 @@ export class EntitySubrecordComponent implements OnChanges { /** columns displayed in the template's table */ @Input() columnsToDisplay = []; - @Output() rowClicked = new EventEmitter(); + @Input() showEntity = (entity: Entity, creatingNew = false) => + this.showEntityInForm(entity, creatingNew); /** data displayed in the template's table */ recordsDataSource = new MatTableDataSource>(); @@ -305,31 +304,34 @@ export class EntitySubrecordComponent implements OnChanges { this.records.unshift(newRecord); this.recordsDataSource.data = [newRow].concat(this.recordsDataSource.data); - newRow.formGroup.enable(); - this.rowClicked.emit(newRecord); + this.showEntity(newRecord, true); } /** * Show one record's details in a modal dialog (if configured). * @param row The entity whose details should be displayed. */ - showRecord(row: TableRow) { + rowClick(row: TableRow) { if (!row.formGroup || row.formGroup.disabled) { - this.rowClicked.emit(row.record); - const dialogRef = this.dialog.open(FormComponent, { - width: "80%", - }); - const columnsCopy = []; - this.columns.forEach((col) => { - const newCol = {}; - Object.assign(newCol, col); - columnsCopy.push([newCol]); - }); - dialogRef.componentInstance.columns = columnsCopy; - dialogRef.componentInstance.entity = row.record; + this.showEntity(row.record); } } + private showEntityInForm(entity: Entity, creatingNew = false) { + const dialogRef = this.dialog.open(FormComponent, { + width: "80%", + }); + const columnsCopy = []; + this.columns.forEach((col) => { + const newCol = {}; + Object.assign(newCol, col); + columnsCopy.push([newCol]); + }); + dialogRef.componentInstance.columns = columnsCopy; + dialogRef.componentInstance.entity = entity; + dialogRef.componentInstance.creatingNew = creatingNew; + } + /** * resets columnsToDisplay depending on current screensize */ diff --git a/src/app/features/historical-data/historical-data.module.ts b/src/app/features/historical-data/historical-data.module.ts index 69fb4d80a2..9fc9538af0 100644 --- a/src/app/features/historical-data/historical-data.module.ts +++ b/src/app/features/historical-data/historical-data.module.ts @@ -2,10 +2,11 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { HistoricalDataComponent } from "./historical-data/historical-data.component"; import { EntitySubrecordModule } from "../../core/entity-components/entity-subrecord/entity-subrecord.module"; +import { EntityUtilsModule } from "../../core/entity-components/entity-utils/entity-utils.module"; @NgModule({ declarations: [HistoricalDataComponent], - imports: [CommonModule, EntitySubrecordModule], + imports: [CommonModule, EntitySubrecordModule, EntityUtilsModule], exports: [HistoricalDataComponent], }) export class HistoricalDataModule {} diff --git a/src/app/features/historical-data/historical-data/historical-data.stories.ts b/src/app/features/historical-data/historical-data/historical-data.stories.ts index 56a16986f0..49b86c8b75 100644 --- a/src/app/features/historical-data/historical-data/historical-data.stories.ts +++ b/src/app/features/historical-data/historical-data/historical-data.stories.ts @@ -13,6 +13,7 @@ import { HistoricalEntityData } from "../historical-entity-data"; import { HistoricalDataComponent } from "./historical-data.component"; import { HistoricalDataModule } from "../historical-data.module"; import { HistoricalDataService } from "../historical-data.service"; +import { EntityPermissionsService } from "../../../core/permissions/entity-permissions.service"; export default { title: "Core/EntityComponents/HistoricalDataComponent", @@ -47,6 +48,10 @@ export default { Promise.resolve([new Test(), new Test(), new Test()]), }, }, + { + provide: EntityPermissionsService, + useValue: { userIsPermitted: () => true }, + }, ], }), ], @@ -103,95 +108,96 @@ Primary.args = { { placeholder: "Date", id: "date", - input: "EditDate", + edit: "EditDate", view: "DisplayDate", }, { placeholder: "Name of Observer", - input: "EditText", + edit: "EditText", view: "DisplayText", id: "nameOfObserver", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "firstQuestion", placeholder: "1. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "secondQuestion", placeholder: "2. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "thirdQuestion", placeholder: "3. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "fourthQuestion", placeholder: "4. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "fifthQuestion", placeholder: "5. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "sixthQuestion", placeholder: "6. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "seventhQuestion", placeholder: "7. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "eightQuestion", placeholder: "8. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "ninthQuestion", placeholder: "9. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, { - input: "EditConfigurableEnum", + edit: "EditConfigurableEnum", view: "DisplayConfigurableEnum", id: "tenthQuestion", placeholder: "10. Question", additional: "rating-answer", - tooltip: "Child admits sown guilt in conflict situations.", + tooltip: "Child admits own guilt in conflict situations.", }, ], entries: [new Test(), new Test(), new Test()], + entity: new Test(), }; From 504ae9cf0e9472229eeccd4262953efc5931ac9d Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 1 Jun 2021 10:44:35 +0200 Subject: [PATCH 139/230] fixed attendance details component --- .../attendance-details.stories.ts | 13 ++++++++++++- src/app/child-dev-project/notes/notes.module.ts | 1 + .../entity-subrecord/entity-subrecord.component.ts | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/app/child-dev-project/attendance/attendance-details/attendance-details.stories.ts b/src/app/child-dev-project/attendance/attendance-details/attendance-details.stories.ts index c70b9fe3c8..f6d1f3f3fb 100644 --- a/src/app/child-dev-project/attendance/attendance-details/attendance-details.stories.ts +++ b/src/app/child-dev-project/attendance/attendance-details/attendance-details.stories.ts @@ -15,6 +15,8 @@ import { Angulartics2Module } from "angulartics2"; import { FontAwesomeIconsModule } from "../../../core/icons/font-awesome-icons.module"; import { MatNativeDateModule } from "@angular/material/core"; import { EntitySubrecordModule } from "../../../core/entity-components/entity-subrecord/entity-subrecord.module"; +import { MatDialogRef } from "@angular/material/dialog"; +import { NotesModule } from "../../notes/notes.module"; const demoActivity = RecurringActivity.create("Coaching Batch C"); const activityAttendance = ActivityAttendance.create(new Date("2020-01-01"), [ @@ -64,10 +66,19 @@ export default { FontAwesomeIconsModule, RouterTestingModule, MatNativeDateModule, + NotesModule, Angulartics2Module.forRoot(), ], declarations: [], - providers: [{ provide: EntityMapperService, useValue: {} }], + providers: [ + { + provide: EntityMapperService, + useValue: { + loadType: () => Promise.resolve([]), + }, + }, + { provide: MatDialogRef, useValue: {} }, + ], }), ], } as Meta; diff --git a/src/app/child-dev-project/notes/notes.module.ts b/src/app/child-dev-project/notes/notes.module.ts index 34c77dfb2f..d036122eb4 100644 --- a/src/app/child-dev-project/notes/notes.module.ts +++ b/src/app/child-dev-project/notes/notes.module.ts @@ -97,5 +97,6 @@ import { EntityUtilsModule } from "../../core/entity-components/entity-utils/ent EntityUtilsModule, ], providers: [], + entryComponents: [NoteDetailsComponent], }) export class NotesModule {} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index b126a06be7..722b38f4f8 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -120,6 +120,9 @@ export class EntitySubrecordComponent implements OnChanges { ) { this.initFormGroups(); this.initDefaultSort(); + if (this.columnsToDisplay.length < 2) { + this.setupTable(); + } } if (changes.hasOwnProperty("columnsToDisplay")) { this.mediaSubscription.unsubscribe(); From d4035d0d4d79261adaf96bd1528b5e2b2f79e1e8 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 1 Jun 2021 15:34:15 +0200 Subject: [PATCH 140/230] refactored entity form service --- .../core/entity-components/entity-utils/entity-form.service.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/core/entity-components/entity-utils/entity-form.service.ts b/src/app/core/entity-components/entity-utils/entity-form.service.ts index 879c870d46..fc212e74c2 100644 --- a/src/app/core/entity-components/entity-utils/entity-form.service.ts +++ b/src/app/core/entity-components/entity-utils/entity-form.service.ts @@ -24,7 +24,6 @@ export class EntityFormService { try { this.addFormFields(formField, entity, forTable); } catch (err) { - console.log(`Could not create form config for ${formField.id}: ${err}`); throw new Error( `Could not create form config for ${formField.id}: ${err}` ); @@ -40,13 +39,13 @@ export class EntityFormService { formField.view = formField.view || this.entitySchemaService.getComponent(propertySchema, "view"); - formField.placeholder = formField.placeholder || propertySchema.label; if (forTable) { formField.forTable = true; formField.placeholder = propertySchema?.labelShort || formField.placeholder; } else { formField.forTable = false; + formField.placeholder = formField.placeholder || propertySchema.label; } } From dfa4de2ecc1efc2c53db51c436c95215f796acd2 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 1 Jun 2021 16:12:57 +0200 Subject: [PATCH 141/230] moved form component --- .../aser/aser-component/aser.component.ts | 2 +- .../activity-attendance-section.component.ts | 2 +- .../attendance-details.component.ts | 2 +- .../educational-material.component.ts | 2 +- .../health-checkup.component.ts | 2 +- .../notes-of-child.component.ts | 2 +- .../previous-schools.component.ts | 2 +- .../children-overview.component.ts | 2 +- .../entity-details/entity-details.module.ts | 5 +- .../entity-form/entity-form.module.ts | 22 ++++ .../entity-form.service.ts | 10 +- .../entity-form}/FormConfig.ts | 0 .../entity-form/entity-form.component.html} | 6 +- .../entity-form/entity-form.component.scss} | 0 .../entity-form.component.spec.ts} | 31 ++--- .../entity-form/entity-form.component.ts} | 28 ++--- .../entity-form/entity-form.stories.ts} | 114 +++++++++--------- .../entity-list/EntityListConfig.ts | 2 +- .../entity-list/entity-list.component.ts | 2 +- .../entity-list/entity-list.module.ts | 2 + .../entity-subrecord.component.spec.ts | 2 +- .../entity-subrecord.component.ts | 8 +- .../entity-subrecord.stories.ts | 2 +- .../dynamic-form-components/edit-component.ts | 2 +- .../edit-single-entity.component.spec.ts | 2 +- .../entity-utils/entity-form.service.spec.ts | 2 +- src/app/core/view/dynamic-components-map.ts | 4 +- .../historical-data.component.ts | 2 +- .../historical-data.stories.ts | 2 +- 29 files changed, 141 insertions(+), 123 deletions(-) create mode 100644 src/app/core/entity-components/entity-form/entity-form.module.ts rename src/app/core/entity-components/{entity-utils => entity-form}/entity-form.service.ts (94%) rename src/app/core/entity-components/{entity-details/form => entity-form/entity-form}/FormConfig.ts (100%) rename src/app/core/entity-components/{entity-details/form/form.component.html => entity-form/entity-form/entity-form.component.html} (91%) rename src/app/core/entity-components/{entity-details/form/form.component.scss => entity-form/entity-form/entity-form.component.scss} (100%) rename src/app/core/entity-components/{entity-details/form/form.component.spec.ts => entity-form/entity-form/entity-form.component.spec.ts} (93%) rename src/app/core/entity-components/{entity-details/form/form.component.ts => entity-form/entity-form/entity-form.component.ts} (80%) rename src/app/core/entity-components/{entity-details/form/form.stories.ts => entity-form/entity-form/entity-form.stories.ts} (61%) diff --git a/src/app/child-dev-project/aser/aser-component/aser.component.ts b/src/app/child-dev-project/aser/aser-component/aser.component.ts index f1053985df..77fc1335e3 100644 --- a/src/app/child-dev-project/aser/aser-component/aser.component.ts +++ b/src/app/child-dev-project/aser/aser-component/aser.component.ts @@ -5,7 +5,7 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Child } from "../../children/model/child"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; @UntilDestroy() @Component({ diff --git a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts index 3f9e18e451..6ea3ac8136 100644 --- a/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts +++ b/src/app/child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component.ts @@ -7,7 +7,7 @@ import { PercentPipe } from "@angular/common"; import { ActivityAttendance } from "../model/activity-attendance"; import { Note } from "../../notes/model/note"; import moment from "moment"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; import { FormDialogService } from "../../../core/form-dialog/form-dialog.service"; @Component({ diff --git a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts index ecc2e5f227..46b83eafa5 100644 --- a/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts +++ b/src/app/child-dev-project/attendance/attendance-details/attendance-details.component.ts @@ -6,7 +6,7 @@ import { Note } from "../../notes/model/note"; import { calculateAverageAttendance } from "../model/calculate-average-event-attendance"; import { NullAttendanceStatusType } from "../model/attendance-status"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; import { FormDialogService } from "../../../core/form-dialog/form-dialog.service"; import { EventNote } from "../model/event-note"; diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index 71f85858f0..687cbc544f 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -5,7 +5,7 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Child } from "../../children/model/child"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; @UntilDestroy() @Component({ diff --git a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts index 4455216807..eaa26ec2ce 100644 --- a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts +++ b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts @@ -5,7 +5,7 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Child } from "../../children/model/child"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; @UntilDestroy() @Component({ diff --git a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts index d43ce2a209..706fccd740 100644 --- a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts +++ b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts @@ -8,7 +8,7 @@ import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { Child } from "../../children/model/child"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; import { FormDialogService } from "../../../core/form-dialog/form-dialog.service"; /** diff --git a/src/app/child-dev-project/previous-schools/previous-schools.component.ts b/src/app/child-dev-project/previous-schools/previous-schools.component.ts index 3e8793f864..f91b73cc22 100644 --- a/src/app/child-dev-project/previous-schools/previous-schools.component.ts +++ b/src/app/child-dev-project/previous-schools/previous-schools.component.ts @@ -4,7 +4,7 @@ import { ChildrenService } from "../children/children.service"; import { Child } from "../children/model/child"; import { OnInitDynamicComponent } from "../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../core/entity-components/entity-form/entity-form/FormConfig"; import moment from "moment"; @Component({ diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts index 1fb8010d88..ba7a34ea1b 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts @@ -3,7 +3,7 @@ import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on import { SchoolsService } from "../schools.service"; import { Child } from "../../children/model/child"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { FormFieldConfig } from "../../../core/entity-components/entity-details/form/FormConfig"; +import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; import { Router } from "@angular/router"; /** diff --git a/src/app/core/entity-components/entity-details/entity-details.module.ts b/src/app/core/entity-components/entity-details/entity-details.module.ts index 55a73f1f41..8923a0f2a8 100644 --- a/src/app/core/entity-components/entity-details/entity-details.module.ts +++ b/src/app/core/entity-components/entity-details/entity-details.module.ts @@ -1,7 +1,6 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; import { EntityDetailsComponent } from "./entity-details.component"; -import { FormComponent } from "./form/form.component"; import { ReactiveFormsModule } from "@angular/forms"; import { MatIconModule } from "@angular/material/icon"; import { MatTooltipModule } from "@angular/material/tooltip"; @@ -17,7 +16,7 @@ import { AlertsModule } from "../../alerts/alerts.module"; import { PermissionsModule } from "../../permissions/permissions.module"; @NgModule({ - declarations: [EntityDetailsComponent, FormComponent], + declarations: [EntityDetailsComponent], imports: [ CommonModule, ReactiveFormsModule, @@ -34,6 +33,6 @@ import { PermissionsModule } from "../../permissions/permissions.module"; PermissionsModule, MatTooltipModule, ], - entryComponents: [FormComponent], + entryComponents: [], }) export class EntityDetailsModule {} diff --git a/src/app/core/entity-components/entity-form/entity-form.module.ts b/src/app/core/entity-components/entity-form/entity-form.module.ts new file mode 100644 index 0000000000..7f0a10b21d --- /dev/null +++ b/src/app/core/entity-components/entity-form/entity-form.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { EntityFormComponent } from "./entity-form/entity-form.component"; +import { EntityFormService } from "./entity-form.service"; +import { MatButtonModule } from "@angular/material/button"; +import { FlexModule } from "@angular/flex-layout"; +import { ViewModule } from "../../view/view.module"; +import { PermissionsModule } from "../../permissions/permissions.module"; + +@NgModule({ + declarations: [EntityFormComponent], + imports: [ + CommonModule, + MatButtonModule, + FlexModule, + ViewModule, + PermissionsModule, + ], + providers: [EntityFormService], + entryComponents: [EntityFormComponent], +}) +export class EntityFormModule {} diff --git a/src/app/core/entity-components/entity-utils/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts similarity index 94% rename from src/app/core/entity-components/entity-utils/entity-form.service.ts rename to src/app/core/entity-components/entity-form/entity-form.service.ts index fc212e74c2..b1ef72ea9e 100644 --- a/src/app/core/entity-components/entity-utils/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -1,13 +1,11 @@ import { Injectable } from "@angular/core"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { FormFieldConfig } from "../entity-details/form/FormConfig"; +import { FormFieldConfig } from "./entity-form/FormConfig"; import { Entity } from "../../entity/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; -@Injectable({ - providedIn: "root", -}) +@Injectable() export class EntityFormService { constructor( private fb: FormBuilder, @@ -42,7 +40,9 @@ export class EntityFormService { if (forTable) { formField.forTable = true; formField.placeholder = - propertySchema?.labelShort || formField.placeholder; + formField.placeholder || + propertySchema.labelShort || + propertySchema.label; } else { formField.forTable = false; formField.placeholder = formField.placeholder || propertySchema.label; diff --git a/src/app/core/entity-components/entity-details/form/FormConfig.ts b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts similarity index 100% rename from src/app/core/entity-components/entity-details/form/FormConfig.ts rename to src/app/core/entity-components/entity-form/entity-form/FormConfig.ts diff --git a/src/app/core/entity-components/entity-details/form/form.component.html b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.html similarity index 91% rename from src/app/core/entity-components/entity-details/form/form.component.html rename to src/app/core/entity-components/entity-form/entity-form/entity-form.component.html index d99eb79b87..a261f8663f 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.html +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.html @@ -23,7 +23,7 @@
+


diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index 22472896a2..aa1fb18b14 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -12,6 +12,7 @@ import { EntityMapperService } from "../../entity/entity-mapper.service"; import { AttendanceMigrationService } from "../../../child-dev-project/attendance/attendance-migration/attendance-migration.service"; import { NotesMigrationService } from "../../../child-dev-project/notes/notes-migration/notes-migration.service"; import { ChildrenMigrationService } from "../../../child-dev-project/children/child-photo-service/children-migration.service"; +import { ConfigMigrationService } from "../../config/config-migration.service"; /** * Admin GUI giving administrative users different options/actions. @@ -41,7 +42,8 @@ export class AdminComponent implements OnInit { private entityMapper: EntityMapperService, public attendanceMigration: AttendanceMigrationService, public notesMigration: NotesMigrationService, - public childrenMigrationService: ChildrenMigrationService + public childrenMigrationService: ChildrenMigrationService, + public configMigrationService: ConfigMigrationService ) {} ngOnInit() { @@ -92,7 +94,6 @@ export class AdminComponent implements OnInit { this.entityMapper, JSON.parse(loadedFile) ); - await this.configService.loadConfig(this.entityMapper); } private startDownload(data: string, type: string, name: string) { diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 5ba3549c10..0747ac4262 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -54,6 +54,12 @@ describe("ConfigMigrationService", () => { title: "Center", id: "center", }, + { + component: "ChildBlockList", + title: "Children", + id: "children", + noSorting: true, + }, ], columnGroup: { default: "School Info", @@ -318,6 +324,13 @@ const expectedChildrenListConfig = { label: "Center", id: "center", }, + { + view: "DisplayEntityArray", + title: "Children", + id: "children", + additional: "Child", + noSorting: true, + }, ], columnGroups: { default: "School Info", diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 4f9abeb5f9..b616f0f485 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -3,7 +3,6 @@ import { ConfigService } from "./config.service"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { Config } from "./config"; import { ViewConfig } from "../view/dynamic-routing/view-config.interface"; -import { RouterService } from "../view/dynamic-routing/router.service"; import { ConfigurableEnumFilterConfig, EntityListConfig, @@ -43,9 +42,7 @@ export class ConfigMigrationService { async migrateConfig(): Promise { this.config = await this.configService.loadConfig(this.entityMapper); - const viewConfigs = this.configService.getAllConfigs( - RouterService.PREFIX_VIEW_CONFIG - ); + const viewConfigs = this.configService.getAllConfigs("view:"); viewConfigs.forEach((viewConfig) => { const entity = this.getEntity(viewConfig._id); if (this.entityListComponents.includes(viewConfig.component)) { @@ -60,8 +57,13 @@ export class ConfigMigrationService { } private getEntity(viewId: string): EntityConstructor { - let entityType = viewId.split(":")[1]; - entityType = entityType[0].toUpperCase() + entityType.slice(1); + const entityType = viewId + .split(":")[1] + .replace("/", "") + .split("-") + .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) + .join(""); + console.log("Loading Entity", entityType, viewId); return ENTITY_MAP.get(entityType); } @@ -69,10 +71,14 @@ export class ConfigMigrationService { config: EntityListConfig, entity: EntityConstructor ) { - config.columnGroups = config["columnGroup"]; - delete config["columnGroup"]; + if (config.hasOwnProperty("columnGroup")) { + config.columnGroups = config["columnGroup"]; + delete config["columnGroup"]; + } this.migrateColumnConfigs(config.columns as FormFieldConfig[], entity); - this.migrateFilters(config.filters); + if (config.hasOwnProperty("filters")) { + this.migrateFilters(config.filters); + } } private migrateColumnConfigs( @@ -99,6 +105,11 @@ export class ConfigMigrationService { column.additional = "User"; column.noSorting = true; } + if (column.view === "ChildBlockList") { + column.view = "DisplayEntityArray"; + column.additional = "Child"; + column.noSorting = true; + } this.addLabelToEntity(column.label, column.id, entity, "short"); } catch (e) { console.warn(`Failed to migrate column ${column.id}: ${e}`); @@ -174,7 +185,9 @@ export class ConfigMigrationService { break; } case "PreviousSchools": { - this.migratePreviousSchoolsComponent(panelComp.config["columns"]); + if (panelComp.hasOwnProperty("config")) { + this.migratePreviousSchoolsComponent(panelComp.config["columns"]); + } break; } case "HistoricalDataComponent": { diff --git a/src/app/core/config/config.service.ts b/src/app/core/config/config.service.ts index 903c369a3d..ae76c27a61 100644 --- a/src/app/core/config/config.service.ts +++ b/src/app/core/config/config.service.ts @@ -41,12 +41,14 @@ export class ConfigService { }); } - public saveConfig( + public async saveConfig( entityMapper: EntityMapperService, config: any ): Promise { this.config.data = config; - return entityMapper.save(this.config); + this.configUpdated.next(this.config); + await entityMapper.save(this.config); + return this.config; } public async exportConfig( diff --git a/src/app/core/entity-components/entity-details/entity-details.component.ts b/src/app/core/entity-components/entity-details/entity-details.component.ts index dc63b356b0..99b60b3410 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.ts @@ -20,6 +20,7 @@ import { OperationType, } from "../../permissions/entity-permissions.service"; import { User } from "../../user/user"; +import { Note } from "../../../child-dev-project/notes/model/note"; export const ENTITY_MAP: Map> = new Map< string, @@ -30,6 +31,7 @@ export const ENTITY_MAP: Map> = new Map< ["School", School], ["Team", School], ["RecurringActivity", RecurringActivity], + ["Note", Note], ["User", User], ]); diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html index 42d4415539..6cad085afd 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html @@ -38,7 +38,7 @@ - + From f2c21d422f61be85668c537ff2eb5f06c7f4a7a8 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 9 Jun 2021 08:18:21 +0200 Subject: [PATCH 165/230] added migration for PreviousTeamsComponent --- .../core/admin/admin/admin.component.spec.ts | 1 - .../config/config-migration.service.spec.ts | 34 ++++++++++++++++- .../core/config/config-migration.service.ts | 38 ++++++++++++++++++- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/app/core/admin/admin/admin.component.spec.ts b/src/app/core/admin/admin/admin.component.spec.ts index b6bffa5a5e..3e36b05b26 100644 --- a/src/app/core/admin/admin/admin.component.spec.ts +++ b/src/app/core/admin/admin/admin.component.spec.ts @@ -167,7 +167,6 @@ describe("AdminComponent", () => { tick(); expect(mockFileReader.readAsText).toHaveBeenCalled(); expect(mockConfigService.saveConfig).toHaveBeenCalled(); - expect(mockConfigService.loadConfig).toHaveBeenCalled(); })); it("should open dialog and call backup service when loading backup", fakeAsync(() => { diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 0747ac4262..8e4793b960 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -202,6 +202,10 @@ describe("ConfigMigrationService", () => { ], }, }, + { + title: "Participation History", + component: "PreviousTeams", + }, ], }, { @@ -326,7 +330,7 @@ const expectedChildrenListConfig = { }, { view: "DisplayEntityArray", - title: "Children", + label: "Children", id: "children", additional: "Child", noSorting: true, @@ -496,6 +500,34 @@ const expectedChildDetailsConfig = { ], }, }, + { + title: "Participation History", + component: "PreviousSchools", + config: { + single: false, + columns: [ + { + id: "schoolId", + label: "Team", + view: "DisplayEntity", + edit: "EditSingleEntity", + additional: "Team", + }, + { + id: "start", + label: "From", + view: "DisplayDate", + edit: "EditDate", + }, + { + id: "end", + label: "To", + view: "DisplayDate", + edit: "EditDate", + }, + ], + }, + }, ], }, { diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index b616f0f485..cde069bff7 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -134,8 +134,7 @@ export class ConfigMigrationService { EntityConfigService.PREFIX_ENTITY_CONFIG + entity.ENTITY_TYPE; let configSchema = this.configService.getConfig(schemaKey); if (!configSchema) { - // @ts-ignore - this.configService.config.data[schemaKey] = {}; + this.config.data[schemaKey] = {}; configSchema = this.configService.getConfig(schemaKey); } if (!configSchema.attributes) { @@ -190,6 +189,10 @@ export class ConfigMigrationService { } break; } + case "PreviousTeams": { + this.migratePreviousTeams(panelComp); + break; + } case "HistoricalDataComponent": { this.migrateHistoricalDataComponent(panelComp.config as any); break; @@ -266,6 +269,37 @@ export class ConfigMigrationService { } } + private migratePreviousTeams(config: PanelComponent) { + config.component = "PreviousSchools"; + config.config = { + single: false, + columns: [ + { + id: "schoolId", + label: "Team", + view: "DisplayEntity", + edit: "EditSingleEntity", + additional: "Team", + }, + { + id: "start", + label: "From", + view: "DisplayDate", + edit: "EditDate", + }, + { + id: "end", + label: "To", + view: "DisplayDate", + edit: "EditDate", + }, + ], + } as any; + this.addLabelToEntity("Team", "schoolId", ChildSchoolRelation, "long"); + this.addLabelToEntity("From", "start", ChildSchoolRelation, "long"); + this.addLabelToEntity("To", "end", ChildSchoolRelation, "long"); + } + private migrateEntitySubrecordInput( formField: FormFieldConfig, inputKey: string From 1b9f12e563ed9789587349145e80bd861dbbdead Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Wed, 9 Jun 2021 09:15:08 +0200 Subject: [PATCH 166/230] refactor: move photo path logic to service --- .../child-photo-service/child-photo.service.spec.ts | 4 +++- .../child-photo-service/child-photo.service.ts | 10 +++++++++- src/app/child-dev-project/children/model/child.ts | 8 -------- .../core/admin/services/child-photo-update.service.ts | 3 ++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts index b914b9d91c..070f272b17 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.spec.ts @@ -56,7 +56,9 @@ describe("ChildPhotoService", () => { const actualImage = await service.getImage(testChild); - expect(actualImage).toBe(Child.generatePhotoPath(testChild.photo.path)); + expect(actualImage).toBe( + ChildPhotoService.generatePhotoPath(testChild.photo.path) + ); }); it("should getFile default if neither webdav nor assets has the file", async () => { diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index 2f072e7522..a0f6337e1b 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -12,7 +12,15 @@ export class ChildPhotoService { if (!photoFile || photoFile.trim() === "") { return ChildPhotoService.getDefaultImage(); } - return Child.generatePhotoPath(photoFile); + return ChildPhotoService.generatePhotoPath(photoFile); + } + + /** + * Returns the full relative filePath to a child photo given a filename, adding the relevant folders to it. + * @param filename The given filename with file extension. + */ + public static generatePhotoPath(filename: string): string { + return "assets/child-photos/" + filename; } public static getDefaultImage(): SafeUrl { diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 44b6dba07a..3dbffb93b9 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -33,14 +33,6 @@ export class Child extends Entity { return instance; } - /** - * Returns the full relative filePath to a child photo given a filename, adding the relevant folders to it. - * @param filename The given filename with file extension. - */ - public static generatePhotoPath(filename: string): string { - return "assets/child-photos/" + filename; - } - @DatabaseField() name: string; @DatabaseField() projectNumber: string; // project number @DatabaseField({ dataType: "date-only" }) dateOfBirth: Date; diff --git a/src/app/core/admin/services/child-photo-update.service.ts b/src/app/core/admin/services/child-photo-update.service.ts index 72a5974db4..bd31a5a0ee 100644 --- a/src/app/core/admin/services/child-photo-update.service.ts +++ b/src/app/core/admin/services/child-photo-update.service.ts @@ -2,6 +2,7 @@ import { Injectable } from "@angular/core"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { HttpClient } from "@angular/common/http"; import { Child } from "../../../child-dev-project/children/model/child"; +import { ChildPhotoService } from "../../../child-dev-project/children/child-photo-service/child-photo.service"; /** * Utility service to automatically detect and update filenames for Child entities' photos. @@ -39,7 +40,7 @@ export class ChildPhotoUpdateService { } const fileExists = await this.checkIfFileExists( - Child.generatePhotoPath(filename) + ChildPhotoService.generatePhotoPath(filename) ); if (fileExists) { const currentPhoto = child.photo; From a0749651d0feba21eb463b7b1a6e2793408cbe1d Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 9 Jun 2021 09:22:38 +0200 Subject: [PATCH 167/230] added migration for all components using displayedColumns --- .../aser/aser-component/aser.component.ts | 6 +-- .../educational-material.component.ts | 6 +-- .../health-checkup.component.ts | 6 +-- .../notes-of-child.component.ts | 6 +-- .../children-overview.component.ts | 4 +- .../config/config-migration.service.spec.ts | 37 +++++++++++++++++++ .../core/config/config-migration.service.ts | 37 +++++++++++++++++++ 7 files changed, 84 insertions(+), 18 deletions(-) diff --git a/src/app/child-dev-project/aser/aser-component/aser.component.ts b/src/app/child-dev-project/aser/aser-component/aser.component.ts index 77fc1335e3..319f066ddc 100644 --- a/src/app/child-dev-project/aser/aser-component/aser.component.ts +++ b/src/app/child-dev-project/aser/aser-component/aser.component.ts @@ -38,10 +38,8 @@ export class AserComponent implements OnChanges, OnInitDynamicComponent { } onInitFromDynamicConfig(config: PanelConfig) { - if (config?.config?.displayedColumns) { - this.columns = this.columns.filter((c) => - config.config.displayedColumns.includes(c.id) - ); + if (config?.config?.columns) { + this.columns = config.config.columns; } this.child = config.entity as Child; diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index 687cbc544f..5120ba8a67 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -35,10 +35,8 @@ export class EducationalMaterialComponent } onInitFromDynamicConfig(config: PanelConfig) { - if (config?.config?.displayedColumns) { - this.columns = this.columns.filter((c) => - config.config.displayedColumns.includes(c.id) - ); + if (config?.config?.columns) { + this.columns = config.config.columns; } this.child = config.entity as Child; diff --git a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts index a3ff7d346b..c3e699650a 100644 --- a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts +++ b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.component.ts @@ -42,10 +42,8 @@ export class HealthCheckupComponent } onInitFromDynamicConfig(config: PanelConfig) { - if (config?.config?.displayedColumns) { - this.columns = this.columns.filter((c) => - config.config.displayedColumns.includes(c.id) - ); + if (config?.config?.columns) { + this.columns = config.config.columns; } this.child = config.entity as Child; diff --git a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts index 706fccd740..1fd54cadd3 100644 --- a/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts +++ b/src/app/child-dev-project/notes/notes-of-child/notes-of-child.component.ts @@ -46,10 +46,8 @@ export class NotesOfChildComponent } onInitFromDynamicConfig(config: PanelConfig) { - if (config?.config?.displayedColumns) { - this.columns = this.columns.filter((c) => - config.config.displayedColumns.includes(c.id) - ); + if (config?.config?.columns) { + this.columns = config.config.columns; } this.child = config.entity as Child; diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts index e97d6e04a9..6e924c0a4f 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.ts @@ -31,8 +31,8 @@ export class ChildrenOverviewComponent implements OnInitDynamicComponent { constructor(private schoolsService: SchoolsService, private router: Router) {} async onInitFromDynamicConfig(config: PanelConfig) { - if (config?.config?.displayedColumns) { - this.columns = config.config.displayedColumns; + if (config?.config?.columns) { + this.columns = config.config.columns; } this.children = await this.schoolsService.getChildrenForSchool( config.entity.getId() diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 8e4793b960..3b90bf760b 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -235,6 +235,21 @@ describe("ConfigMigrationService", () => { }, ], }, + { + title: "", + component: "ChildrenOverview", + config: { + displayedColumns: ["name", "schoolClass", "age"], + }, + }, + + { + title: "", + component: "Aser", + config: { + displayedColumns: ["date", "math", "hindi"], + }, + }, ], }, { @@ -560,6 +575,28 @@ const expectedChildDetailsConfig = { }, ], }, + { + title: "", + component: "ChildrenOverview", + config: { + columns: [ + "name", + { id: "schoolClass", label: "Class", view: "DisplayText" }, + { id: "age", label: "Age", view: "DisplayText" }, + ], + }, + }, + { + title: "", + component: "Aser", + config: { + columns: [ + { id: "date", visibleFrom: "xs" }, + { id: "math", visibleFrom: "xs" }, + { id: "hindi", visibleFrom: "md" }, + ], + }, + }, ], }, { diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index cde069bff7..082dc08f63 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -22,6 +22,7 @@ import { import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; import { HistoricalEntityData } from "../../features/historical-data/historical-entity-data"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; +import { HealthCheck } from "../../child-dev-project/health-checkup/model/health-check"; @Injectable({ providedIn: "root", @@ -201,6 +202,16 @@ export class ConfigMigrationService { this.migrateActivityParticipantsSection(panelComp); break; } + case "Aser": + case "EducationalMaterial": + case "HealthCheckup": + case "NotesOfChild": + case "ChildrenOverview": { + if (panelComp.hasOwnProperty("config")) { + this.migrateTable(panelComp.config); + } + break; + } } }); }); @@ -392,4 +403,30 @@ export class ConfigMigrationService { "long" ); } + + private migrateTable(config: any) { + const columnConfigs = [ + { id: "date", visibleFrom: "xs" }, + { id: "materialType", visibleFrom: "xs" }, + { id: "materialAmount", visibleFrom: "md" }, + { id: "description", visibleFrom: "md" }, + { id: "math", visibleFrom: "xs" }, + { id: "english", visibleFrom: "xs" }, + { id: "hindi", visibleFrom: "md" }, + { id: "bengali", visibleFrom: "md" }, + { id: "remarks", visibleFrom: "md" }, + { id: "schoolClass", label: "Class", view: "DisplayText" }, + { id: "age", label: "Age", view: "DisplayText" }, + { + id: "bmi", + label: "BMI", + view: "ReadonlyFunction", + additional: (entity: HealthCheck) => entity.bmi.toFixed(2), + }, + ]; + config.columns = config.displayedColumns.map((col: string) => { + return columnConfigs.find((cc) => cc.id === col) || col; + }); + delete config.displayedColumns; + } } From d93a054ffbe032dc32c8b35b9c6462561f89eb81 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 9 Jun 2021 10:15:50 +0200 Subject: [PATCH 168/230] fixed default value --- .../children/child-photo-service/datatype-photo.ts | 1 + src/app/child-dev-project/children/model/child.ts | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index ae67ec46c7..053af2bf52 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -54,6 +54,7 @@ export class PhotoDatatype implements EntitySchemaDatatype { return { path: value, photo: new BehaviorSubject( + // reactivate the integration of cloud file loading here after testing and performance improvements ChildPhotoService.getImageFromAssets(value) ), }; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 44b6dba07a..1227e800ef 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -22,7 +22,6 @@ import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; import { calculateAge } from "../../../utils/utils"; import { Photo } from "../child-photo-service/photo"; -import { ChildPhotoService } from "../child-photo-service/child-photo.service"; export type Center = ConfigurableEnumValue; @DatabaseEntity("Child") @@ -63,7 +62,7 @@ export class Child extends Entity { @DatabaseField({ dataType: "photo", - defaultValue: ChildPhotoService.getDefaultImage(), + defaultValue: "", }) photo: Photo; From 103f6f63eb82f02785a6383e0d9e6b630cbbc6ea Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 9 Jun 2021 10:29:12 +0200 Subject: [PATCH 169/230] added documentation --- .../child-photo-service/datatype-photo.spec.ts | 2 +- .../children/child-photo-service/photo.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 64b04691eb..2fe1b6de5a 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -54,7 +54,7 @@ describe("dataType photo", () => { it("should set the default photo when loading", () => { class TestEntity extends Entity { - @DatabaseField({ dataType: "photo", defaultValue: true }) + @DatabaseField({ dataType: "photo", defaultValue: "" }) photo: Photo; } const defaultImg = "default-img"; diff --git a/src/app/child-dev-project/children/child-photo-service/photo.ts b/src/app/child-dev-project/children/child-photo-service/photo.ts index fdaad011b3..e578166752 100644 --- a/src/app/child-dev-project/children/child-photo-service/photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/photo.ts @@ -1,7 +1,19 @@ import { BehaviorSubject } from "rxjs"; import { SafeUrl } from "@angular/platform-browser"; +/** + * A simple interface for creating photo attributes. + */ export interface Photo { + /** + * The path to the photo. This will be saved to the database. + */ path: string; + + /** + * The actual photo which can be used in a template: + * `` + * This is not saved to the database but build from the `path` attribute when loaded from the database. + */ photo: BehaviorSubject; } From ee6637cc6fe0b5c846e08a8e86717ed9152af454 Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Mon, 14 Jun 2021 16:18:19 +0200 Subject: [PATCH 170/230] only save changed objects after photo migration --- .../children-migration.service.ts | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts index 64d88a97d9..d86fbee559 100644 --- a/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/children-migration.service.ts @@ -1,26 +1,30 @@ import { Injectable } from "@angular/core"; import { Database } from "../../../core/database/database"; import { Child } from "../model/child"; +import { LoggingService } from "../../../core/logging/logging.service"; @Injectable({ providedIn: "root", }) export class ChildrenMigrationService { - constructor(private database: Database) {} + constructor(private database: Database, private logging: LoggingService) {} async migratePhotoFormat(): Promise { - const allChildren = await this.database.getAll(Child.ENTITY_TYPE + ":"); - allChildren.forEach((child) => { - if ( - child.hasOwnProperty("photoFile") && - child["photoFile"].trim() !== "" - ) { - const photoFile = child["photoFile"]; - delete child.photoFile; - child["photo"] = photoFile; - } + const oldFormatChildren = ( + await this.database.getAll(Child.ENTITY_TYPE + ":") + ).filter( + (child) => + child.hasOwnProperty("photoFile") && child["photoFile"].trim() !== "" + ); + oldFormatChildren.forEach((child) => { + const photoFile = child["photoFile"]; + delete child.photoFile; + child["photo"] = photoFile; }); - await Promise.all(allChildren.map((child) => this.database.put(child))); + await Promise.all( + oldFormatChildren.map((child) => this.database.put(child)) + ); + this.logging.info(`migrated ${oldFormatChildren.length} objects`); } } From 77c6028074a266cde632b12a70921c223b6ca12f Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Wed, 16 Jun 2021 12:02:22 +0200 Subject: [PATCH 171/230] avoid merge changes --- .../children/child-photo-service/child-photo.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts index 1ebc3749b0..a0f6337e1b 100644 --- a/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts +++ b/src/app/child-dev-project/children/child-photo-service/child-photo.service.ts @@ -10,7 +10,7 @@ import { BehaviorSubject } from "rxjs"; export class ChildPhotoService { public static getImageFromAssets(photoFile: string): SafeUrl { if (!photoFile || photoFile.trim() === "") { - return "assets/child.png"; + return ChildPhotoService.getDefaultImage(); } return ChildPhotoService.generatePhotoPath(photoFile); } @@ -23,6 +23,10 @@ export class ChildPhotoService { return "assets/child-photos/" + filename; } + public static getDefaultImage(): SafeUrl { + return "assets/child.png"; + } + private basePath = "photos/"; constructor(@Optional() private cloudFileService: CloudFileService) {} From c80410241c77be62787679e369e6dafae425c8b5 Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Wed, 23 Jun 2021 12:08:49 +0200 Subject: [PATCH 172/230] move paginator component to entity-subrecord where it is actually needed --- .../entity-list/entity-list.module.ts | 15 ++------------- .../entity-subrecord/entity-subrecord.module.ts | 7 ++++++- .../list-paginator/list-paginator.component.html | 0 .../list-paginator/list-paginator.component.scss | 0 .../list-paginator.component.spec.ts | 2 +- .../list-paginator/list-paginator.component.ts | 0 6 files changed, 9 insertions(+), 15 deletions(-) rename src/app/core/entity-components/{entity-list => entity-subrecord}/list-paginator/list-paginator.component.html (100%) rename src/app/core/entity-components/{entity-list => entity-subrecord}/list-paginator/list-paginator.component.scss (100%) rename src/app/core/entity-components/{entity-list => entity-subrecord}/list-paginator/list-paginator.component.spec.ts (97%) rename src/app/core/entity-components/{entity-list => entity-subrecord}/list-paginator/list-paginator.component.ts (100%) diff --git a/src/app/core/entity-components/entity-list/entity-list.module.ts b/src/app/core/entity-components/entity-list/entity-list.module.ts index cc520953cf..77cd4cd04b 100644 --- a/src/app/core/entity-components/entity-list/entity-list.module.ts +++ b/src/app/core/entity-components/entity-list/entity-list.module.ts @@ -8,7 +8,6 @@ import { Angulartics2Module } from "angulartics2"; import { MatButtonModule } from "@angular/material/button"; import { ExtendedModule, FlexModule } from "@angular/flex-layout"; import { MatInputModule } from "@angular/material/input"; -import { MatToolbarModule } from "@angular/material/toolbar"; import { MatCheckboxModule } from "@angular/material/checkbox"; import { MatExpansionModule } from "@angular/material/expansion"; import { MatButtonToggleModule } from "@angular/material/button-toggle"; @@ -19,18 +18,11 @@ import { FormsModule } from "@angular/forms"; import { AdminModule } from "../../admin/admin.module"; import { ViewModule } from "../../view/view.module"; import { ListFilterComponent } from "./list-filter/list-filter.component"; -import { ListPaginatorComponent } from "./list-paginator/list-paginator.component"; import { PermissionsModule } from "../../permissions/permissions.module"; import { EntitySubrecordModule } from "../entity-subrecord/entity-subrecord.module"; -import { MatSliderModule } from "@angular/material/slider"; -import { MatSlideToggleModule } from "@angular/material/slide-toggle"; @NgModule({ - declarations: [ - EntityListComponent, - ListFilterComponent, - ListPaginatorComponent, - ], + declarations: [EntityListComponent, ListFilterComponent], imports: [ CommonModule, FormsModule, @@ -47,15 +39,12 @@ import { MatSlideToggleModule } from "@angular/material/slide-toggle"; ExtendedModule, MatButtonToggleModule, MatTableModule, - MatToolbarModule, ViewModule, MatSortModule, MatPaginatorModule, PermissionsModule, EntitySubrecordModule, - MatSliderModule, - MatSlideToggleModule, ], - exports: [EntityListComponent, ListPaginatorComponent], + exports: [EntityListComponent], }) export class EntityListModule {} diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts index 8181309f28..825b318cb0 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord.module.ts @@ -14,9 +14,12 @@ import { MatTooltipModule } from "@angular/material/tooltip"; import { ViewModule } from "../../view/view.module"; import { ReactiveFormsModule } from "@angular/forms"; import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation-dialog.module"; +import { ListPaginatorComponent } from "./list-paginator/list-paginator.component"; +import { MatSlideToggleModule } from "@angular/material/slide-toggle"; +import { MatToolbarModule } from "@angular/material/toolbar"; @NgModule({ - declarations: [EntitySubrecordComponent, KeysPipe], + declarations: [EntitySubrecordComponent, KeysPipe, ListPaginatorComponent], imports: [ CommonModule, AlertsModule, @@ -31,6 +34,8 @@ import { ConfirmationDialogModule } from "../../confirmation-dialog/confirmation MatTooltipModule, MatButtonModule, MatIconModule, + MatSlideToggleModule, + MatToolbarModule, ], exports: [EntitySubrecordComponent, KeysPipe], }) diff --git a/src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.html b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.html similarity index 100% rename from src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.html rename to src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.html diff --git a/src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.scss b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.scss similarity index 100% rename from src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.scss rename to src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.scss diff --git a/src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.spec.ts b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.spec.ts similarity index 97% rename from src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.spec.ts rename to src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.spec.ts index d079f301c8..1dd4d4384b 100644 --- a/src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.spec.ts @@ -7,7 +7,7 @@ import { } from "@angular/core/testing"; import { ListPaginatorComponent } from "./list-paginator.component"; -import { EntityListModule } from "../entity-list.module"; +import { EntityListModule } from "../../entity-list/entity-list.module"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { SessionService } from "../../../session/session-service/session.service"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; diff --git a/src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.ts b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts similarity index 100% rename from src/app/core/entity-components/entity-list/list-paginator/list-paginator.component.ts rename to src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts From f48c987a10c64f3102d9b513ca6e8b71c6bf9473 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 23 Jun 2021 17:39:10 +0200 Subject: [PATCH 173/230] refactored validation function --- .../children/model/childSchoolRelation.ts | 21 +++++++------------ .../entity-form/entity-form.service.ts | 19 ++++++++++------- src/app/core/entity/entity.ts | 12 ++++++----- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.ts b/src/app/child-dev-project/children/model/childSchoolRelation.ts index 53262b0ebf..53651a1040 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.ts @@ -3,27 +3,19 @@ import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import moment from "moment"; import { School } from "../../schools/model/school"; -import { FormGroup } from "@angular/forms"; /** * Record of a school year that a Child attended a certain class in a School. */ @DatabaseEntity("ChildSchoolRelation") export class ChildSchoolRelation extends Entity { - static validateForm(formGroup: FormGroup) { - super.validateForm(formGroup); - const school = formGroup.get("schoolId")?.value; - const schoolLabel = ChildSchoolRelation.schema.get("schoolId").label; - const startDate: Date = formGroup.get("start")?.value; - const startLabel = ChildSchoolRelation.schema.get("start").label; - const endDate: Date = formGroup.get("end")?.value; - const endLabel = ChildSchoolRelation.schema.get("end").label; - if (!school) { - throw new Error(`No "${schoolLabel}" selected`); - } - if (endDate && !startDate) { + assertValid() { + super.assertValid(); + const startLabel = this.getSchema().get("start").label; + const endLabel = this.getSchema().get("end").label; + if (this.end && !this.start) { throw new Error(`No "${startLabel}" date is set`); - } else if (moment(startDate).isAfter(endDate, "days")) { + } else if (moment(this.start).isAfter(this.end, "days")) { throw new Error( `The "${startLabel}" date is after the "${endLabel}" date` ); @@ -36,6 +28,7 @@ export class ChildSchoolRelation extends Entity { viewComponent: "DisplayEntity", editComponent: "EditSingleEntity", additional: School.ENTITY_TYPE, + required: true, }) schoolId: string; @DatabaseField({ label: "Class" }) schoolClass: string = ""; diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 03cd49bf7f..4567b260cb 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -67,14 +67,19 @@ export class EntityFormService { public saveChanges(form: FormGroup, entity: Entity): Promise { this.checkFormValidity(form); const entityConstructor = entity.getConstructor(); - entityConstructor.validateForm(form); + const tmpEntity = entity.copy(); - this.assignFormValuesToEntity(form, entity); - return this.entityMapper.save(entity).catch((err) => { - throw new Error( - `Could not save ${entityConstructor.ENTITY_TYPE}: ${err}` - ); - }); + this.assignFormValuesToEntity(form, tmpEntity); + entity.assertValid(); + + return this.entityMapper + .save(tmpEntity) + .then(() => Object.assign(entity, tmpEntity)) + .catch((err) => { + throw new Error( + `Could not save ${entityConstructor.ENTITY_TYPE}: ${err}` + ); + }); } private checkFormValidity(form: FormGroup) { diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/entity.ts index b2a4c990c5..fd2eb3e73e 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/entity.ts @@ -22,7 +22,6 @@ import { WarningLevel, WarningLevelColor, } from "../../child-dev-project/warning-level"; -import { FormGroup } from "@angular/forms"; /** * This represents a static class of type . @@ -93,10 +92,6 @@ export class Entity { } } - static validateForm(formGroup: FormGroup) { - return; - } - static getBlockComponent(): string { return; } @@ -230,4 +225,11 @@ export class Entity { Object.assign(other, this); return other; } + + /** + * Checks if the entity is valid and if the check fails, throws an error explaining the failed check. + */ + assertValid(): void { + return; + } } From dbb296fb184226bf3510a2ffbc96055a01ae319b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 08:10:44 +0200 Subject: [PATCH 174/230] fixed unit tests --- .../children-overview/children-overview.component.spec.ts | 8 ++++++++ .../entity-subrecord/entity-subrecord.component.spec.ts | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts b/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts index 1b7a9e5ced..ec51660e8b 100644 --- a/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts +++ b/src/app/child-dev-project/schools/children-overview/children-overview.component.spec.ts @@ -14,6 +14,8 @@ import { RouterTestingModule } from "@angular/router/testing"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { Router } from "@angular/router"; import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; +import { SessionService } from "../../../core/session/session-service/session.service"; +import { User } from "../../../core/user/user"; describe("ChildrenOverviewComponent", () => { let component: ChildrenOverviewComponent; @@ -25,12 +27,18 @@ describe("ChildrenOverviewComponent", () => { beforeEach( waitForAsync(() => { + const mockSessionService = jasmine.createSpyObj([ + "getCurrentUser", + ]); + mockSessionService.getCurrentUser.and.returnValue(new User()); + TestBed.configureTestingModule({ declarations: [], imports: [SchoolsModule, RouterTestingModule, NoopAnimationsModule], providers: [ { provide: SchoolsService, useValue: schoolsService }, { provide: EntityMapperService, useValue: {} }, + { provide: SessionService, useValue: mockSessionService }, ], }).compileComponents(); }) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 0aac3b8e01..09dfe88b89 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -28,6 +28,8 @@ import { EntityFormService } from "../../entity-form/entity-form.service"; import { Subject } from "rxjs"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { MatSnackBar } from "@angular/material/snack-bar"; +import { SessionService } from "../../../session/session-service/session.service"; +import { User } from "../../../user/user"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -37,6 +39,10 @@ describe("EntitySubrecordComponent", () => { beforeEach( waitForAsync(() => { mockEntityMapper = jasmine.createSpyObj(["remove", "save"]); + const mockSessionService = jasmine.createSpyObj([ + "getCurrentUser", + ]); + mockSessionService.getCurrentUser.and.returnValue(new User()); TestBed.configureTestingModule({ imports: [ @@ -49,6 +55,7 @@ describe("EntitySubrecordComponent", () => { DatePipe, PercentPipe, { provide: EntityMapperService, useValue: mockEntityMapper }, + { provide: SessionService, useValue: mockSessionService }, ], }).compileComponents(); }) From bc64417b752abf61954b3c8a43a304ebe551b250 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 08:21:22 +0200 Subject: [PATCH 175/230] fixed unit tests --- .../model/childSchoolRelation.spec.ts | 40 +++++++------------ .../changelog/changelog.component.spec.ts | 1 + 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts index 5ff9a90cf9..5ccae6cbeb 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts @@ -20,7 +20,6 @@ import { ChildSchoolRelation } from "./childSchoolRelation"; import { Entity } from "../../../core/entity/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import moment from "moment"; -import { FormBuilder } from "@angular/forms"; describe("ChildSchoolRelation Entity", () => { const ENTITY_TYPE = "ChildSchoolRelation"; @@ -100,37 +99,26 @@ describe("ChildSchoolRelation Entity", () => { expect(relation.isActive).toBeTrue(); }); - it("should fail validation when no school is defined", () => { - const formGroup = new FormBuilder().group({ schoolId: null }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); - }); - it("should fail validation when end date but no start date is defined", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - end: new Date(), - start: null, - }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.end = new Date(); + expect(() => relation.assertValid()).toThrowError(); }); it("should fail validation when start date is after end date", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - start: moment().add(1, "day"), - end: new Date(), - }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.start = moment().add(1, "day").toDate(); + relation.end = new Date(); + expect(() => relation.assertValid()).toThrowError(); }); it("does pass validation when the start date is before the end date", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - start: moment().subtract(1, "day"), - end: new Date(), - }); - expect(() => - ChildSchoolRelation.validateForm(formGroup) - ).not.toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.start = moment().subtract(1, "day").toDate(); + relation.end = new Date(); + expect(() => relation.assertValid()).not.toThrowError(); }); }); diff --git a/src/app/core/latest-changes/changelog/changelog.component.spec.ts b/src/app/core/latest-changes/changelog/changelog.component.spec.ts index 52d1425c1a..bbd76e52ef 100644 --- a/src/app/core/latest-changes/changelog/changelog.component.spec.ts +++ b/src/app/core/latest-changes/changelog/changelog.component.spec.ts @@ -42,6 +42,7 @@ describe("ChangelogComponent", () => { waitForAsync(() => { mockLatestChangesService = jasmine.createSpyObj([ "getChangelogsBeforeVersion", + "getChangelogsBetweenVersions", ]); TestBed.configureTestingModule({ From 268acc827cd8924596149108188b1686fbc3f210 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 08:49:59 +0200 Subject: [PATCH 176/230] fixed member ordering --- .../entity-subrecord/entity-subrecord.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 4d2dc638ad..1d2191c6e7 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -72,9 +72,6 @@ export class EntitySubrecordComponent implements OnChanges { /** columns displayed in the template's table */ @Input() columnsToDisplay = []; - @Input() showEntity = (entity: Entity, creatingNew = false) => - this.showEntityInForm(entity, creatingNew); - /** data displayed in the template's table */ recordsDataSource = new MatTableDataSource>(); @@ -108,6 +105,9 @@ export class EntitySubrecordComponent implements OnChanges { /** function returns the background color for each entry*/ @Input() getBackgroundColor?: (rec: T) => string = (rec: T) => rec.getColor(); + @Input() showEntity = (entity: Entity, creatingNew = false) => + this.showEntityInForm(entity, creatingNew); + /** * Update the component if any of the @Input properties were changed from outside. * @param changes From e50eaafb9f7bca00c5cb20499028a23958763563 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 09:12:01 +0200 Subject: [PATCH 177/230] added tests for entity validation --- .../entity-form/entity-form.service.spec.ts | 24 ++++++++++++++++++- .../entity-form/entity-form.service.ts | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index 4276f2db25..e3aea80265 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -1,10 +1,11 @@ -import { TestBed } from "@angular/core/testing"; +import { fakeAsync, TestBed, tick } from "@angular/core/testing"; import { EntityFormService } from "./entity-form.service"; import { FormBuilder } from "@angular/forms"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { EntityFormModule } from "./entity-form.module"; +import { Entity } from "../../entity/entity"; describe("EntityFormService", () => { let service: EntityFormService; @@ -27,4 +28,25 @@ describe("EntityFormService", () => { it("should be created", () => { expect(service).toBeTruthy(); }); + + it("should not save invalid entities", () => { + const entity = new Entity("initialId"); + const tmpEntity = new Entity(); + spyOn(entity, "copy").and.returnValue(tmpEntity); + spyOn(tmpEntity, "assertValid").and.throwError(new Error()); + const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); + + expect(() => service.saveChanges(formGroup, entity)).toThrowError(); + expect(entity.getId()).toBe("initialId"); + }); + + it("should update initial entity if saving is successful", fakeAsync(() => { + const entity = new Entity("initialId"); + const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); + + service.saveChanges(formGroup, entity); + tick(); + + expect(entity.getId()).toBe("newId"); + })); }); diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 4567b260cb..3686566d13 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -70,7 +70,7 @@ export class EntityFormService { const tmpEntity = entity.copy(); this.assignFormValuesToEntity(form, tmpEntity); - entity.assertValid(); + tmpEntity.assertValid(); return this.entityMapper .save(tmpEntity) From 3d1ebb91a60991bd253c0b119c0123058e5f8f96 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 09:15:52 +0200 Subject: [PATCH 178/230] fixed failing test --- .../entity-subrecord/entity-subrecord.component.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 09dfe88b89..4502b4fed7 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -317,7 +317,7 @@ describe("EntitySubrecordComponent", () => { expect(component.records).toEqual([child]); })); - it("should create new entities and make them editable", fakeAsync(() => { + it("should create new entities and make them editable", () => { const child = new Child(); component.newRecordFactory = () => child; component.columns = [{ id: "name" }, { id: "projectNumber" }]; @@ -329,7 +329,7 @@ describe("EntitySubrecordComponent", () => { (row) => row.record === child ); expect(tableRow.formGroup.enabled).toBeTrue(); - })); + }); it("should notify when an entity is clicked", (done) => { const child = new Child(); From bacd2a011777aea14b7d6c97ee9d6e029e5a3477 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 09:57:54 +0200 Subject: [PATCH 179/230] refactored reading and math levels --- .../aser/demo-aser-generator.service.ts | 17 +-- .../child-dev-project/aser/model/aser.spec.ts | 14 +-- src/app/child-dev-project/aser/model/aser.ts | 108 ++++++++++++------ src/app/core/config/config-fix.ts | 8 ++ .../changelog/changelog.component.spec.ts | 7 +- 5 files changed, 104 insertions(+), 50 deletions(-) diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index e42c10bd37..aaeb780b33 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -4,7 +4,8 @@ import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; import { WarningLevel } from "../warning-level"; -import { Aser } from "./model/aser"; +import { Aser, mathLevels, readingLevels } from "./model/aser"; +import { ConfigurableEnumValue } from "../../core/configurable-enum/configurable-enum.interface"; /** * Generate ASER results every 12 months for each Child until passing. @@ -47,15 +48,15 @@ export class DemoAserGeneratorService extends DemoDataGenerator { aserResult.child = child.getId(); aserResult.date = date; aserResult.math = this.selectNextSkillLevel( - Aser.MathLevels, + mathLevels, previousResult.math ); aserResult.english = this.selectNextSkillLevel( - Aser.ReadingLevels, + readingLevels, previousResult.english ); aserResult[firstLanguage] = this.selectNextSkillLevel( - Aser.ReadingLevels, + readingLevels, previousResult[firstLanguage] ); @@ -73,13 +74,13 @@ export class DemoAserGeneratorService extends DemoDataGenerator { /** * Randomly select the next Aser level for a skill based on the previous result. - * @param skillRange The array of skill levels for the desired subject (Aser.MathLevels or Aser.ReadingLevels) + * @param skillRange The array of skill levels for the desired subject (mathLevels or readingLevels) * @param previousSkillLevel The string indicating the level from the previous test for this subject */ private selectNextSkillLevel( - skillRange: string[], - previousSkillLevel: string - ): string { + skillRange: ConfigurableEnumValue[], + previousSkillLevel: ConfigurableEnumValue + ): ConfigurableEnumValue { const previousSkillLevelIndex = skillRange.indexOf(previousSkillLevel); let nextSkillLevelIndex; diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index a58e5f4463..7fce20d324 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Aser } from "./aser"; +import { Aser, mathLevels, readingLevels } from "./aser"; import { WarningLevel } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; @@ -50,10 +50,10 @@ describe("Aser", () => { child: "1", date: new Date(), - hindi: "Read Sentence", - bengali: "Nothing", - english: "Read Letters", - math: "Subtraction", + hindi: readingLevels[2], + bengali: readingLevels[1], + english: readingLevels[2], + math: mathLevels[4], remarks: "nothing to remark", searchIndices: [], @@ -83,8 +83,8 @@ describe("Aser", () => { it("warning level WARNING if some bad results", function () { const id = "test1"; const entity = new Aser(id); - entity.english = Aser.ReadingLevels[0]; - entity.math = Aser.MathLevels[1]; + entity.english = readingLevels[1]; + entity.math = readingLevels[2]; expect(entity.getWarningLevel()).toBe(WarningLevel.WARNING); }); diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index be68c026f3..4be3ead8cb 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -19,67 +19,107 @@ import { Entity } from "../../../core/entity/entity"; import { WarningLevel } from "../../warning-level"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const readingLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "nothing", + label: "Nothing", + }, + { + id: "read_letters", + label: "Read Letters", + }, + { + id: "read_words", + label: "Read Words", + }, + { + id: "read_sentence", + label: "Read Sentence", + }, + { + id: "read_paragraph", + label: "Read Paragraph", + }, +]; + +export const mathLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "nothing", + label: "Nothing", + }, + { + id: "numbers1to9", + label: "Numbers 1-9", + }, + { + id: "numbers10to99", + label: "Numbers 10-99", + }, + { + id: "subtraction", + label: "Subtraction", + }, + { + id: "division", + label: "Division", + }, +]; @DatabaseEntity("Aser") export class Aser extends Entity { - static ReadingLevels = [ - "Nothing", - "Read Letters", - "Read Words", - "Read Sentence", - "Read Paragraph", - ]; - static MathLevels = [ - "Nothing", - "Numbers 1-9", - "Numbers 10-99", - "Subtraction", - "Division", - ]; - - static isReadingPassedOrNA(level: string) { - if (level === "" || level === undefined) { + static isReadingPassedOrNA(level: ConfigurableEnumValue) { + if (!level || level.id === "") { // not applicable return true; } - return level === this.ReadingLevels[4]; + return level === readingLevels[5]; } - static isMathPassedOrNA(level: string) { - if (level === "" || level === undefined) { + static isMathPassedOrNA(level: ConfigurableEnumValue) { + if (!level || level.id === "") { // not applicable return true; } - return level === this.MathLevels[4]; + return level === mathLevels[5]; } @DatabaseField() child: string; // id of Child entity - @DatabaseField({ label: "Date", additional: Aser.ReadingLevels }) + @DatabaseField({ label: "Date" }) date: Date = new Date(); @DatabaseField({ label: "Hindi", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - hindi: string = ""; + hindi: ConfigurableEnumValue; @DatabaseField({ label: "Bengali", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - bengali: string = ""; + bengali: ConfigurableEnumValue; @DatabaseField({ label: "English", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - english: string = ""; + english: ConfigurableEnumValue; @DatabaseField({ label: "Math", - editComponent: "EditSelectable", - additional: Aser.MathLevels, + dataType: "configurable-enum", + innerDataType: "math-levels", }) - math: string = ""; + math: ConfigurableEnumValue; @DatabaseField({ label: "Remarks" }) remarks: string = ""; getWarningLevel(): WarningLevel { diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index c77038590c..6830ec116a 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -5,6 +5,10 @@ import { Gender } from "../../child-dev-project/children/model/Gender"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; import { EventNote } from "../../child-dev-project/attendance/model/event-note"; +import { + mathLevels, + readingLevels, +} from "../../child-dev-project/aser/model/aser"; // prettier-ignore export const defaultJsonConfig = { @@ -78,6 +82,10 @@ export const defaultJsonConfig = { "enum:attendance-status": defaultAttendanceStatusTypes, + "enum:reading-levels": readingLevels, + + "enum:math-levels": mathLevels, + "enum:document-status": [ { "id": "", diff --git a/src/app/core/latest-changes/changelog/changelog.component.spec.ts b/src/app/core/latest-changes/changelog/changelog.component.spec.ts index bbd76e52ef..f9c7a217a7 100644 --- a/src/app/core/latest-changes/changelog/changelog.component.spec.ts +++ b/src/app/core/latest-changes/changelog/changelog.component.spec.ts @@ -25,6 +25,7 @@ import { of } from "rxjs"; import { LatestChangesModule } from "../latest-changes.module"; import { SwUpdate } from "@angular/service-worker"; import { MarkdownModule } from "ngx-markdown"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; describe("ChangelogComponent", () => { let component: ChangelogComponent; @@ -46,7 +47,11 @@ describe("ChangelogComponent", () => { ]); TestBed.configureTestingModule({ - imports: [LatestChangesModule, MarkdownModule.forRoot()], + imports: [ + LatestChangesModule, + MarkdownModule.forRoot(), + NoopAnimationsModule, + ], providers: [ { provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: of([testChangelog]) }, From e805019e102ca9a4259c4fd48677cea09c64c7b1 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 11:48:58 +0200 Subject: [PATCH 180/230] refactored gender as configurable enum --- .../children/children.service.spec.ts | 8 +- .../demo-child-generator.service.ts | 4 +- .../children/model/Gender.ts | 4 - .../children/model/child.spec.ts | 6 +- .../child-dev-project/children/model/child.ts | 8 +- .../children/model/genders.ts | 16 ++++ src/app/core/config/config-fix.ts | 16 ++-- .../core/config/config-migration.service.ts | 1 - .../entity-subrecord.component.spec.ts | 6 +- .../features/reporting/query.service.spec.ts | 22 +++--- .../reporting/reporting.service.spec.ts | 76 +++++++++---------- .../reporting/reporting/reporting.stories.ts | 7 +- 12 files changed, 92 insertions(+), 82 deletions(-) delete mode 100644 src/app/child-dev-project/children/model/Gender.ts create mode 100644 src/app/child-dev-project/children/model/genders.ts diff --git a/src/app/child-dev-project/children/children.service.spec.ts b/src/app/child-dev-project/children/children.service.spec.ts index 4d3fc57fe6..82410b00c8 100644 --- a/src/app/child-dev-project/children/children.service.spec.ts +++ b/src/app/child-dev-project/children/children.service.spec.ts @@ -3,13 +3,13 @@ import { EntityMapperService } from "../../core/entity/entity-mapper.service"; import { ChildSchoolRelation } from "./model/childSchoolRelation"; import { Child } from "./model/child"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; -import { Gender } from "./model/Gender"; import { School } from "../schools/model/school"; import { TestBed } from "@angular/core/testing"; import moment from "moment"; import { Database } from "../../core/database/database"; import { Note } from "../notes/model/note"; import { PouchDatabase } from "../../core/database/pouch-database"; +import { genders } from "./model/genders"; describe("ChildrenService", () => { let service: ChildrenService; @@ -196,7 +196,7 @@ function generateChildEntities(): Child[] { a1.name = "Arjun A."; a1.projectNumber = "1"; a1.religion = "Hindu"; - a1.gender = Gender.MALE; + a1.gender = genders[1]; a1.dateOfBirth = new Date("2000-03-13"); a1.motherTongue = "Hindi"; a1.center = { id: "delhi", label: "Delhi" }; @@ -206,7 +206,7 @@ function generateChildEntities(): Child[] { a2.name = "Bandana B."; a2.projectNumber = "2"; a2.religion = "Hindu"; - a2.gender = Gender.FEMALE; + a2.gender = genders[2]; a2.dateOfBirth = new Date("2001-01-01"); a2.motherTongue = "Bengali"; a2.center = { id: "kolkata", label: "Kolkata" }; @@ -216,7 +216,7 @@ function generateChildEntities(): Child[] { a3.name = "Chandan C."; a3.projectNumber = "3"; a3.religion = "Hindu"; - a3.gender = Gender.MALE; + a3.gender = genders[1]; a3.dateOfBirth = new Date("2002-07-29"); a3.motherTongue = "Hindi"; a3.center = { id: "kolkata", label: "Kolkata" }; diff --git a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts index 44e2758f96..22b3e30443 100644 --- a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts +++ b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts @@ -1,5 +1,4 @@ import { Child } from "../model/child"; -import { Gender } from "../model/Gender"; import { religions } from "./fixtures/religions"; import { languages } from "./fixtures/languages"; import { dropoutTypes } from "./fixtures/dropout-types"; @@ -8,6 +7,7 @@ import { DemoDataGenerator } from "../../../core/demo-data/demo-data-generator"; import { faker } from "../../../core/demo-data/faker"; import { centersWithProbability } from "./fixtures/centers"; import { addDefaultChildPhoto } from "../../../../../.storybook/utils/addDefaultChildPhoto"; +import { genders } from "../model/genders"; export class DemoChildConfig { count: number; @@ -34,7 +34,7 @@ export class DemoChildGenerator extends DemoDataGenerator { child.name = faker.name.firstName() + " " + faker.name.lastName(); child.projectNumber = id; child.religion = faker.random.arrayElement(religions); - child.gender = faker.random.arrayElement([Gender.MALE, Gender.FEMALE]); + child.gender = faker.random.arrayElement(genders.slice(1)); child.dateOfBirth = faker.dateOfBirth(5, 20); child.motherTongue = faker.random.arrayElement(languages); child.center = faker.random.arrayElement(centersWithProbability); diff --git a/src/app/child-dev-project/children/model/Gender.ts b/src/app/child-dev-project/children/model/Gender.ts deleted file mode 100644 index 9ae34d3661..0000000000 --- a/src/app/child-dev-project/children/model/Gender.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Gender { - MALE = "M", - FEMALE = "F", -} diff --git a/src/app/child-dev-project/children/model/child.spec.ts b/src/app/child-dev-project/children/model/child.spec.ts index e978042edc..5dc7ed46e5 100644 --- a/src/app/child-dev-project/children/model/child.spec.ts +++ b/src/app/child-dev-project/children/model/child.spec.ts @@ -18,9 +18,9 @@ import { Child } from "./child"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; -import { Gender } from "./Gender"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { PhotoDatatype } from "../child-photo-service/datatype-photo"; +import { genders } from "./genders"; describe("Child", () => { const ENTITY_TYPE = "Child"; @@ -56,7 +56,7 @@ describe("Child", () => { name: "Max", projectNumber: "1", - gender: "M", + gender: genders[1], dateOfBirth: "2010-01-01", motherTongue: "Hindi", religion: "Hindu", @@ -78,7 +78,7 @@ describe("Child", () => { const entity = new Child(id); entity.name = expectedData.name; entity.projectNumber = expectedData.projectNumber; - entity.gender = Gender.MALE; + entity.gender = expectedData.gender; entity.dateOfBirth = new Date(expectedData.dateOfBirth); entity.motherTongue = expectedData.motherTongue; entity.religion = expectedData.religion; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 0aa093eb6e..d529d6de1b 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -16,7 +16,6 @@ */ import { Entity } from "../../../core/entity/entity"; -import { Gender } from "./Gender"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; @@ -61,12 +60,11 @@ export class Child extends Entity { dateOfBirth: Date; @DatabaseField({ label: "Mother Tongue" }) motherTongue: string = ""; @DatabaseField({ - dataType: "string", + dataType: "configurable-enum", label: "Gender", - additional: ["", "M", "F"], - editComponent: "EditSelectable", + innerDataType: "genders", }) - gender: Gender; // M or F + gender: ConfigurableEnumValue; @DatabaseField({ label: "Religion" }) religion: string = ""; @DatabaseField({ diff --git a/src/app/child-dev-project/children/model/genders.ts b/src/app/child-dev-project/children/model/genders.ts new file mode 100644 index 0000000000..d7ee51416f --- /dev/null +++ b/src/app/child-dev-project/children/model/genders.ts @@ -0,0 +1,16 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const genders: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "M", + label: "male", + }, + { + id: "F", + label: "female", + }, +]; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 6830ec116a..752d1b62f0 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -1,7 +1,6 @@ import { defaultAttendanceStatusTypes } from "./default-config/default-attendance-status-types"; import { defaultInteractionTypes } from "./default-config/default-interaction-types"; import { Child } from "../../child-dev-project/children/model/child"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; import { EventNote } from "../../child-dev-project/attendance/model/event-note"; @@ -9,6 +8,7 @@ import { mathLevels, readingLevels, } from "../../child-dev-project/aser/model/aser"; +import { genders } from "../../child-dev-project/children/model/genders"; // prettier-ignore export const defaultJsonConfig = { @@ -86,6 +86,8 @@ export const defaultJsonConfig = { "enum:math-levels": mathLevels, + "enum:genders": genders, + "enum:document-status": [ { "id": "", @@ -730,8 +732,8 @@ export const defaultJsonConfig = { "query": `${Child.ENTITY_TYPE}:toArray[*isActive=true]`, "label": "All children", "aggregations": [ - {"label": "Male children", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, { @@ -744,8 +746,8 @@ export const defaultJsonConfig = { "query": `[*privateSchool!=true]:getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId)[*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique:toEntities`, "label": "Children attending a governmental school", "aggregations": [ - {"label": "Male children attending a governmental school", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children attending a governmental school", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children attending a governmental school", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children attending a governmental school", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, {"label": "Private schools", "query": `[*privateSchool=true]`}, @@ -753,8 +755,8 @@ export const defaultJsonConfig = { "query": `[*privateSchool=true]:getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId)[*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique:toEntities`, "label": "Children attending a private school", "aggregations": [ - {"label": "Male children attending a private school", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children attending a private school", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children attending a private school", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children attending a private school", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, ] diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 082dc08f63..3cdb421d91 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -64,7 +64,6 @@ export class ConfigMigrationService { .split("-") .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) .join(""); - console.log("Loading Entity", entityType, viewId); return ENTITY_MAP.get(entityType); } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 86497e6014..c17d4a1472 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -24,11 +24,11 @@ import { Note } from "../../../../child-dev-project/notes/model/note"; import { AlertService } from "../../../alerts/alert.service"; import { PageEvent } from "@angular/material/paginator"; import { FormBuilder, FormGroup } from "@angular/forms"; -import { Gender } from "../../../../child-dev-project/children/model/Gender"; import { EntityFormService } from "../../entity-form/entity-form.service"; import { Subject } from "rxjs"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { MatSnackBar } from "@angular/material/snack-bar"; +import { genders } from "../../../../child-dev-project/children/model/genders"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -258,7 +258,7 @@ describe("EntitySubrecordComponent", () => { child.name = "Old Name"; const formGroup = fb.group({ name: "New Name", - gender: Gender.FEMALE, + gender: genders[2], }); component.save({ record: child, formGroup: formGroup }); @@ -266,7 +266,7 @@ describe("EntitySubrecordComponent", () => { expect(mockEntityMapper.save).toHaveBeenCalledWith(child); expect(child.name).toBe("New Name"); - expect(child.gender).toBe(Gender.FEMALE); + expect(child.gender).toBe(genders[2]); expect(formGroup.disabled).toBeTrue(); })); diff --git a/src/app/features/reporting/query.service.spec.ts b/src/app/features/reporting/query.service.spec.ts index 5a4ba4e19f..efaa159899 100644 --- a/src/app/features/reporting/query.service.spec.ts +++ b/src/app/features/reporting/query.service.spec.ts @@ -2,7 +2,6 @@ import { TestBed } from "@angular/core/testing"; import { QueryService } from "./query.service"; import { Child } from "../../child-dev-project/children/model/child"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { EntityMapperService } from "../../core/entity/entity-mapper.service"; import { School } from "../../child-dev-project/schools/model/school"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; @@ -20,6 +19,7 @@ import { expectEntitiesToMatch } from "../../utils/expect-entity-data.spec"; import { Database } from "../../core/database/database"; import { ConfigurableEnumModule } from "../../core/configurable-enum/configurable-enum.module"; import { Note } from "../../child-dev-project/notes/model/note"; +import { genders } from "../../child-dev-project/children/model/genders"; describe("QueryService", () => { let service: QueryService; @@ -66,19 +66,19 @@ describe("QueryService", () => { beforeEach(async () => { const entityMapper = TestBed.inject(EntityMapperService); maleChristianChild = new Child("maleChristianChild"); - maleChristianChild.gender = Gender.MALE; + maleChristianChild.gender = genders[1]; maleChristianChild.religion = "christian"; await entityMapper.save(maleChristianChild); femaleChristianChild = new Child("femaleChristianChild"); - femaleChristianChild.gender = Gender.FEMALE; + femaleChristianChild.gender = genders[2]; femaleChristianChild.religion = "christian"; await entityMapper.save(femaleChristianChild); femaleMuslimChild = new Child("femaleMuslimChild"); - femaleMuslimChild.gender = Gender.FEMALE; + femaleMuslimChild.gender = genders[2]; femaleMuslimChild.religion = "muslim"; await entityMapper.save(femaleMuslimChild); maleChild = new Child("maleChild"); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; await entityMapper.save(maleChild); privateSchool = new School("privateSchool"); @@ -221,11 +221,11 @@ describe("QueryService", () => { }); it("should return all children with specified attributes", async () => { - const maleChristianQuery = `${Child.ENTITY_TYPE}:toArray[*gender=M & religion=christian]`; + const maleChristianQuery = `${Child.ENTITY_TYPE}:toArray:filterByObjectAttribute(gender, id, M)[*religion=christian]`; const maleChristians = await service.queryData(maleChristianQuery); expectEntitiesToMatch(maleChristians, [maleChristianChild]); - const femaleQuery = `${Child.ENTITY_TYPE}:toArray[*gender=F]`; + const femaleQuery = `${Child.ENTITY_TYPE}:toArray:filterByObjectAttribute(gender, id, F)`; const females = await service.queryData(femaleQuery); expectEntitiesToMatch(females, [femaleChristianChild, femaleMuslimChild]); @@ -243,7 +243,7 @@ describe("QueryService", () => { ${School.ENTITY_TYPE}:toArray[*privateSchool=true] :getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId) [*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique - :toEntities[*gender=${Gender.MALE}]`; + :toEntities:filterByObjectAttribute(gender, id, M)`; const maleChildrenOnPrivateSchools = await service.queryData( maleChildrenOnPrivateSchoolsQuery @@ -273,7 +273,7 @@ describe("QueryService", () => { maleChild, ]); - const maleChildrenCountQuery = `[*gender=${Gender.MALE}]:count`; + const maleChildrenCountQuery = `:filterByObjectAttribute(gender, id, M):count`; const maleChildrenCount = await service.queryData( maleChildrenCountQuery, null, @@ -291,7 +291,7 @@ describe("QueryService", () => { ); expect(christianCount).toBe(2); - const maleChristiansCountQuery = `[*gender=${Gender.MALE} & religion=christian]:count`; + const maleChristiansCountQuery = `:filterByObjectAttribute(gender, id, M)[*religion=christian]:count`; const maleChristiansCount = await service.queryData( maleChristiansCountQuery, null, @@ -334,7 +334,7 @@ describe("QueryService", () => { :getRelated(${RecurringActivity.ENTITY_TYPE}, linkedGroups) :getRelated(${EventNote.ENTITY_TYPE}, relatesTo) :getParticipantsWithAttendance(PRESENT):addPrefix(${Child.ENTITY_TYPE}):unique - :toEntities[*gender=${Gender.FEMALE}]`; + :toEntities:filterByObjectAttribute(gender, id, F)`; const femaleParticipantsInPrivateSchools = await service.queryData( femaleParticipantsPrivateSchoolQuery ); diff --git a/src/app/features/reporting/reporting.service.spec.ts b/src/app/features/reporting/reporting.service.spec.ts index 2bf5d4875e..81f20ea596 100644 --- a/src/app/features/reporting/reporting.service.spec.ts +++ b/src/app/features/reporting/reporting.service.spec.ts @@ -7,8 +7,8 @@ import { EventNote } from "../../child-dev-project/attendance/model/event-note"; import moment from "moment"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { centersUnique } from "../../child-dev-project/children/demo-data-generators/fixtures/centers"; +import { genders } from "../../child-dev-project/children/model/genders"; describe("ReportingService", () => { let service: ReportingService; @@ -160,9 +160,9 @@ describe("ReportingService", () => { it("should correctly parse groupBy results", async () => { const maleChild = new Child(); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; const femaleChild = new Child(); - femaleChild.gender = Gender.FEMALE; + femaleChild.gender = genders[2]; mockQueryService.queryData.and.resolveTo([ femaleChild, maleChild, @@ -184,7 +184,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 1, }, subRows: [], @@ -192,7 +192,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [], @@ -204,9 +204,9 @@ describe("ReportingService", () => { it("should run aggregations after a groupBy", async () => { const maleChild = new Child(); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; const femaleChild = new Child(); - femaleChild.gender = Gender.FEMALE; + femaleChild.gender = genders[2]; mockQueryService.queryData.and.resolveTo([ maleChild, femaleChild, @@ -239,14 +239,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [ { header: { label: "Total # of christians", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 3, }, subRows: [], @@ -256,14 +256,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 1, }, subRows: [ { header: { label: "Total # of christians", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 3, }, subRows: [], @@ -279,19 +279,19 @@ describe("ReportingService", () => { const alipore = centersUnique.find((c) => c.id === "alipore"); const barabazar = centersUnique.find((c) => c.id === "barabazar"); const maleChristianAlipore = new Child(); - maleChristianAlipore.gender = Gender.MALE; + maleChristianAlipore.gender = genders[1]; maleChristianAlipore.religion = "christian"; maleChristianAlipore.center = alipore; const maleMuslimAlipore = new Child(); - maleMuslimAlipore.gender = Gender.MALE; + maleMuslimAlipore.gender = genders[1]; maleMuslimAlipore.religion = "muslim"; maleMuslimAlipore.center = alipore; const femaleChristianBarabazar = new Child(); - femaleChristianBarabazar.gender = Gender.FEMALE; + femaleChristianBarabazar.gender = genders[2]; femaleChristianBarabazar.religion = "christian"; femaleChristianBarabazar.center = barabazar; const femaleChristianAlipore = new Child(); - femaleChristianAlipore.gender = Gender.FEMALE; + femaleChristianAlipore.gender = genders[2]; femaleChristianAlipore.religion = "christian"; femaleChristianAlipore.center = alipore; mockQueryService.queryData.and.resolveTo([ @@ -382,7 +382,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 2, }, subRows: [ @@ -390,7 +390,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "center", value: alipore }, ], result: 1, @@ -401,7 +401,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "center", value: barabazar }, ], result: 1, @@ -412,7 +412,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, ], result: 2, @@ -422,7 +422,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, { property: "center", value: alipore }, ], @@ -434,7 +434,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, { property: "center", value: barabazar }, ], @@ -449,7 +449,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [ @@ -457,7 +457,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "center", value: alipore }, ], result: 2, @@ -468,7 +468,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, ], result: 1, @@ -478,7 +478,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, { property: "center", value: alipore }, ], @@ -492,7 +492,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, ], result: 1, @@ -502,7 +502,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, { property: "center", value: alipore }, ], @@ -521,13 +521,13 @@ describe("ReportingService", () => { it("should allow multiple groupBy's", async () => { const femaleMuslim = new Child(); - femaleMuslim.gender = Gender.FEMALE; + femaleMuslim.gender = genders[2]; femaleMuslim.religion = "muslim"; const femaleChristian = new Child(); - femaleChristian.gender = Gender.FEMALE; + femaleChristian.gender = genders[2]; femaleChristian.religion = "christian"; const maleMuslim = new Child(); - maleMuslim.gender = Gender.MALE; + maleMuslim.gender = genders[1]; maleMuslim.religion = "muslim"; mockQueryService.queryData.and.resolveTo([ femaleChristian, @@ -584,14 +584,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 4, }, subRows: [ { header: { label: "Total # of old children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 5, }, subRows: [ @@ -599,7 +599,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, ], result: 2, @@ -610,7 +610,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "muslim" }, ], result: 3, @@ -624,14 +624,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 1, }, subRows: [ { header: { label: "Total # of old children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 5, }, subRows: [ @@ -639,7 +639,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, ], result: 2, @@ -650,7 +650,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, ], result: 3, diff --git a/src/app/features/reporting/reporting/reporting.stories.ts b/src/app/features/reporting/reporting/reporting.stories.ts index 94d3d0941b..02e84417d0 100644 --- a/src/app/features/reporting/reporting/reporting.stories.ts +++ b/src/app/features/reporting/reporting/reporting.stories.ts @@ -9,11 +9,10 @@ import { MatNativeDateModule } from "@angular/material/core"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { FontAwesomeIconsModule } from "../../../core/icons/font-awesome-icons.module"; import { BackupService } from "../../../core/admin/services/backup.service"; -import { Gender } from "../../../child-dev-project/children/model/Gender"; import { ReportingModule } from "../reporting.module"; +import { genders } from "../../../child-dev-project/children/model/genders"; const reportingService = { - setAggregations: () => null, calculateReport: () => { return Promise.resolve([ { @@ -80,7 +79,7 @@ const reportingService = { { header: { label: "Total # of children", - values: [Gender.FEMALE], + values: [genders[2]], result: 2, }, subRows: [ @@ -130,7 +129,7 @@ const reportingService = { { header: { label: "Total # of children", - values: [Gender.MALE], + values: [genders[1]], result: 2, }, subRows: [ From 95893d66ba69777ab58d10f3fe2556e6969e2940 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 12:11:50 +0200 Subject: [PATCH 181/230] refactored material types --- ...-educational-material-generator.service.ts | 9 +- .../educational-material.component.ts | 8 +- .../model/educational-material.ts | 52 +------- .../educational-material/model/materials.ts | 126 ++++++++++++++++++ src/app/core/config/config-fix.ts | 3 + 5 files changed, 143 insertions(+), 55 deletions(-) create mode 100644 src/app/child-dev-project/educational-material/model/materials.ts diff --git a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts index 24d508c162..a1a5011fbe 100644 --- a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts +++ b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts @@ -3,7 +3,8 @@ import { DemoDataGenerator } from "../../core/demo-data/demo-data-generator"; import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; -import { EducationalMaterial } from "./model/educational-material"; +import { EducationalMaterial} from "./model/educational-material"; +import { materials } from "./model/materials"; export class DemoEducationMaterialConfig { minCount: number; @@ -51,7 +52,7 @@ export class DemoEducationalMaterialGeneratorService extends DemoDataGenerator material.hasOwnProperty("color")) ); specialMaterial.materialAmount = 1; data.push(specialMaterial); @@ -69,9 +70,7 @@ export class DemoEducationalMaterialGeneratorService extends DemoDataGenerator(); - materialTypes = EducationalMaterial.MATERIAL_ALL; - columns: FormFieldConfig[] = [ { id: "date", visibleFrom: "xs" }, { id: "materialType", visibleFrom: "xs" }, @@ -77,10 +75,10 @@ export class EducationalMaterialComponent const summary = new Map(); this.records.forEach((m) => { - const previousValue = summary.has(m.materialType) - ? summary.get(m.materialType) + const previousValue = summary.has(m.materialType.id) + ? summary.get(m.materialType.id) : 0; - summary.set(m.materialType, previousValue + m.materialAmount); + summary.set(m.materialType.id, previousValue + m.materialAmount); }); let summaryText = ""; diff --git a/src/app/child-dev-project/educational-material/model/educational-material.ts b/src/app/child-dev-project/educational-material/model/educational-material.ts index 4e311c6082..05b9848de1 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.ts @@ -18,63 +18,25 @@ import { Entity } from "../../../core/entity/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; @DatabaseEntity("EducationalMaterial") export class EducationalMaterial extends Entity { - static MATERIAL_STATIONARIES = [ - "pencil", - "eraser", - "sharpener", - "pen (black)", - "pen (blue)", - "oil pastels", - "crayons", - "sketch pens", - "scale (big)", - "scale (small)", - "geometry box", - "copy (single line, small)", - "copy (single line, big)", - "copy (four line)", - "copy (squared)", - "copy (plain)", - "copy (line-plain)", - "copy (drawing)", - "copy (practical)", - "graph book", - "project papers", - "project file", - "scrap book", - "exam board", - ]; - static MATERIAL_OTHER = [ - "Bag", - "School Uniform", - "School Shoes", - "Sports Dress", - "Sports Shoes", - "Raincoat", - ]; - static MATERIAL_ALL = EducationalMaterial.MATERIAL_STATIONARIES.concat( - EducationalMaterial.MATERIAL_OTHER - ); @DatabaseField() child: string; // id of Child entity @DatabaseField({ label: "Date" }) date: Date; @DatabaseField({ label: "Material", - editComponent: "EditSelectable", - additional: EducationalMaterial.MATERIAL_ALL, + dataType: "configurable-enum", + innerDataType: "materials", }) - materialType = ""; + materialType: ConfigurableEnumValue; @DatabaseField({ label: "Amount" }) materialAmount: number; @DatabaseField({ label: "Description" }) description = ""; public getColor() { - if (EducationalMaterial.MATERIAL_STATIONARIES.includes(this.materialType)) { - return "white"; - } else { - return "#B3E5FC"; - } + return this.materialType && this.materialType["color"] + ? this.materialType["color"] + : "white"; } } diff --git a/src/app/child-dev-project/educational-material/model/materials.ts b/src/app/child-dev-project/educational-material/model/materials.ts new file mode 100644 index 0000000000..e5c6d0a8ed --- /dev/null +++ b/src/app/child-dev-project/educational-material/model/materials.ts @@ -0,0 +1,126 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const materials: ConfigurableEnumValue[] = [ + { + id: "pencil", + label: "pencil", + }, + { + id: "eraser", + label: "eraser", + }, + { + id: "sharpener", + label: "sharpener", + }, + { + id: "pen_black", + label: "pen (black)", + }, + { + id: "oil_pastels", + label: "oil pastels", + }, + { + id: "crayons", + label: "crayons", + }, + { + id: "sketch_pens", + label: "sketch pens", + }, + { + id: "scale_big", + label: "scale (big)", + }, + { + id: "scale_small", + label: "scale (small)", + }, + { + id: "geometry_box", + label: "geometry box", + }, + { + id: "copy_single_small", + label: "copy (single line, small)", + }, + { + id: "copy_single_big", + label: "copy (single line, big)", + }, + { + id: "copy_four", + label: "copy (four line)", + }, + { + id: "copy_squared", + label: "copy (squared)", + }, + { + id: "copy_plain", + label: "copy (plain)", + }, + { + id: "copy_line_plain", + label: "copy (line-plain)", + }, + { + id: "copy_drawing", + label: "copy (drawing)", + }, + { + id: "copy_practical", + label: "copy (practical)", + }, + { + id: "graph_book", + label: "graph book", + }, + { + id: "project_papers", + label: "project papers", + }, + { + id: "project_file", + label: "project file", + }, + { + id: "scrap_book", + label: "scrap book", + }, + { + id: "exam_board", + label: "exam board", + }, + { + id: "bag", + label: "Bag", + color: "#B3E5FC", + }, + { + id: "school_uniform", + label: "School Uniform", + color: "#B3E5FC", + }, + { + id: "school_shoes", + label: "School Shoes", + color: "#B3E5FC", + }, + { + id: "sports_dress", + label: "Sports Dress", + color: "#B3E5FC", + }, + { + id: "sports_shoes", + label: "Sports Shoes", + color: "#B3E5FC", + }, + { + id: "raincoat", + label: "Raincoat", + color: "#B3E5FC", + }, +]; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 752d1b62f0..fb0dafc0f5 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -9,6 +9,7 @@ import { readingLevels, } from "../../child-dev-project/aser/model/aser"; import { genders } from "../../child-dev-project/children/model/genders"; +import { materials } from "../../child-dev-project/educational-material/model/materials"; // prettier-ignore export const defaultJsonConfig = { @@ -88,6 +89,8 @@ export const defaultJsonConfig = { "enum:genders": genders, + "enum:materials": materials, + "enum:document-status": [ { "id": "", From 4f3126b1b20d1d3bc06c859725387355bc91c580 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 13:08:16 +0200 Subject: [PATCH 182/230] added migrations for the new configurable enums --- .../aser/demo-aser-generator.service.ts | 4 +- .../child-dev-project/aser/model/aser.spec.ts | 4 +- src/app/child-dev-project/aser/model/aser.ts | 56 +------------------ .../aser/model/mathLevels.ts | 28 ++++++++++ .../aser/model/readingLevels.ts | 28 ++++++++++ .../model/educational-material.spec.ts | 3 +- src/app/core/admin/admin/admin.component.html | 2 +- src/app/core/admin/admin/admin.component.ts | 9 ++- src/app/core/config/config-fix.ts | 6 +- .../configurable-enum-datatype.ts | 2 +- 10 files changed, 78 insertions(+), 64 deletions(-) create mode 100644 src/app/child-dev-project/aser/model/mathLevels.ts create mode 100644 src/app/child-dev-project/aser/model/readingLevels.ts diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index aaeb780b33..80dfe239e5 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -4,8 +4,10 @@ import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; import { WarningLevel } from "../warning-level"; -import { Aser, mathLevels, readingLevels } from "./model/aser"; +import { Aser } from "./model/aser"; import { ConfigurableEnumValue } from "../../core/configurable-enum/configurable-enum.interface"; +import { mathLevels } from "./model/mathLevels"; +import { readingLevels } from "./model/readingLevels"; /** * Generate ASER results every 12 months for each Child until passing. diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index 7fce20d324..10f8f65eec 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -15,11 +15,13 @@ * along with ndb-core. If not, see . */ -import { Aser, mathLevels, readingLevels } from "./aser"; +import { Aser } from "./aser"; import { WarningLevel } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { mathLevels } from "./mathLevels"; +import { readingLevels } from "./readingLevels"; describe("Aser", () => { const ENTITY_TYPE = "Aser"; diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index 4be3ead8cb..66a37250b7 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -20,60 +20,8 @@ import { WarningLevel } from "../../warning-level"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; - -export const readingLevels: ConfigurableEnumValue[] = [ - { - id: "", - label: "", - }, - { - id: "nothing", - label: "Nothing", - }, - { - id: "read_letters", - label: "Read Letters", - }, - { - id: "read_words", - label: "Read Words", - }, - { - id: "read_sentence", - label: "Read Sentence", - }, - { - id: "read_paragraph", - label: "Read Paragraph", - }, -]; - -export const mathLevels: ConfigurableEnumValue[] = [ - { - id: "", - label: "", - }, - { - id: "nothing", - label: "Nothing", - }, - { - id: "numbers1to9", - label: "Numbers 1-9", - }, - { - id: "numbers10to99", - label: "Numbers 10-99", - }, - { - id: "subtraction", - label: "Subtraction", - }, - { - id: "division", - label: "Division", - }, -]; +import { mathLevels } from "./mathLevels"; +import { readingLevels } from "./readingLevels"; @DatabaseEntity("Aser") export class Aser extends Entity { diff --git a/src/app/child-dev-project/aser/model/mathLevels.ts b/src/app/child-dev-project/aser/model/mathLevels.ts new file mode 100644 index 0000000000..3dd4c5274a --- /dev/null +++ b/src/app/child-dev-project/aser/model/mathLevels.ts @@ -0,0 +1,28 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const mathLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "nothing", + label: "Nothing", + }, + { + id: "numbers1to9", + label: "Numbers 1-9", + }, + { + id: "numbers10to99", + label: "Numbers 10-99", + }, + { + id: "subtraction", + label: "Subtraction", + }, + { + id: "division", + label: "Division", + }, +]; diff --git a/src/app/child-dev-project/aser/model/readingLevels.ts b/src/app/child-dev-project/aser/model/readingLevels.ts new file mode 100644 index 0000000000..bfa1cdd4ef --- /dev/null +++ b/src/app/child-dev-project/aser/model/readingLevels.ts @@ -0,0 +1,28 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const readingLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "nothing", + label: "Nothing", + }, + { + id: "read_letters", + label: "Read Letters", + }, + { + id: "read_words", + label: "Read Words", + }, + { + id: "read_sentence", + label: "Read Sentence", + }, + { + id: "read_paragraph", + label: "Read Paragraph", + }, +]; diff --git a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts index 142373fcca..838a13f26e 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts @@ -19,6 +19,7 @@ import { waitForAsync } from "@angular/core/testing"; import { EducationalMaterial } from "./educational-material"; import { Entity } from "../../../core/entity/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { materials } from "./materials"; describe("EducationalMaterial Entity", () => { const ENTITY_TYPE = "EducationalMaterial"; @@ -54,7 +55,7 @@ describe("EducationalMaterial Entity", () => { child: "1", date: new Date(), - materialType: "foo", + materialType: materials[1], materialAmount: 2, description: "bar", diff --git a/src/app/core/admin/admin/admin.component.html b/src/app/core/admin/admin/admin.component.html index 9b7fb897a2..e9544dadee 100644 --- a/src/app/core/admin/admin/admin.component.html +++ b/src/app/core/admin/admin/admin.component.html @@ -21,7 +21,7 @@

Utility Functions

-

diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index aa1fb18b14..76dbbe2228 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -13,6 +13,7 @@ import { AttendanceMigrationService } from "../../../child-dev-project/attendanc import { NotesMigrationService } from "../../../child-dev-project/notes/notes-migration/notes-migration.service"; import { ChildrenMigrationService } from "../../../child-dev-project/children/child-photo-service/children-migration.service"; import { ConfigMigrationService } from "../../config/config-migration.service"; +import { ConfigurableEnumMigrationService } from "../../configurable-enum/configurable-enum-migration.service"; /** * Admin GUI giving administrative users different options/actions. @@ -43,7 +44,8 @@ export class AdminComponent implements OnInit { public attendanceMigration: AttendanceMigrationService, public notesMigration: NotesMigrationService, public childrenMigrationService: ChildrenMigrationService, - public configMigrationService: ConfigMigrationService + public configMigrationService: ConfigMigrationService, + public configurableEnumMigrationSerivice: ConfigurableEnumMigrationService ) {} ngOnInit() { @@ -58,6 +60,11 @@ export class AdminComponent implements OnInit { this.childPhotoUpdateService.updateChildrenPhotoFilenames(); } + async migrateConfigChanges() { + await this.configMigrationService.migrateConfig(); + await this.configurableEnumMigrationSerivice.migrateSelectionsToConfigurableEnum() + } + /** * Send a reference of the PouchDB to the browser's developer console for real-time debugging. */ diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index fb0dafc0f5..8e763ad853 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -4,12 +4,10 @@ import { Child } from "../../child-dev-project/children/model/child"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; import { EventNote } from "../../child-dev-project/attendance/model/event-note"; -import { - mathLevels, - readingLevels, -} from "../../child-dev-project/aser/model/aser"; import { genders } from "../../child-dev-project/children/model/genders"; import { materials } from "../../child-dev-project/educational-material/model/materials"; +import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; +import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; // prettier-ignore export const defaultJsonConfig = { diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index e911d631f7..ae854f2d79 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -39,6 +39,6 @@ export class ConfigurableEnumDatatype return this.configService .getConfig(enumId) - ?.find((option) => option.id === value); + ?.find((option) => option.id === value || option.label === value); } } From 9b4cbda2d9802e4ab2d0d61e01aaee5fe339459f Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 13:45:39 +0200 Subject: [PATCH 183/230] added test for ensuring that the new enums are available --- src/app/core/config/config-fix.ts | 6 -- .../config/config-migration.service.spec.ts | 9 +++ .../core/config/config-migration.service.ts | 25 +++++- ...onfigurable-enum-migration.service.spec.ts | 80 +++++++++++++++++++ .../configurable-enum-migration.service.ts | 23 ++++++ 5 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts create mode 100644 src/app/core/configurable-enum/configurable-enum-migration.service.ts diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 8e763ad853..3fb5244081 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -78,17 +78,11 @@ export const defaultJsonConfig = { "enum:interaction-type": defaultInteractionTypes, - "enum:attendance-status": defaultAttendanceStatusTypes, - "enum:reading-levels": readingLevels, - "enum:math-levels": mathLevels, - "enum:genders": genders, - "enum:materials": materials, - "enum:document-status": [ { "id": "", diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 3b90bf760b..f5e0e63937 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -5,6 +5,8 @@ import { ConfigService } from "./config.service"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { Config } from "./config"; import { EntityConfig } from "../entity/entity-config.service"; +import { CONFIGURABLE_ENUM_CONFIG_PREFIX } from "../configurable-enum/configurable-enum.interface"; +import { genders } from "../../child-dev-project/children/model/genders"; describe("ConfigMigrationService", () => { let service: ConfigMigrationService; @@ -300,6 +302,13 @@ describe("ConfigMigrationService", () => { const childDetailsConfig = configService.getConfig("view:child/:id"); expect(childDetailsConfig).toEqual(expectedChildDetailsConfig); }); + + it("should add configurable enum configs", () => { + const genderConfig = configService.getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + "genders" + ); + expect(genderConfig).toEqual(genders); + }); }); const expectedChildrenListConfig = { component: "ChildrenList", diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 3cdb421d91..12ace6ac4e 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -23,6 +23,11 @@ import { ChildSchoolRelation } from "../../child-dev-project/children/model/chil import { HistoricalEntityData } from "../../features/historical-data/historical-entity-data"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; import { HealthCheck } from "../../child-dev-project/health-checkup/model/health-check"; +import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; +import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; +import { genders } from "../../child-dev-project/children/model/genders"; +import { materials } from "../../child-dev-project/educational-material/model/materials"; +import { CONFIGURABLE_ENUM_CONFIG_PREFIX } from "../configurable-enum/configurable-enum.interface"; @Injectable({ providedIn: "root", @@ -43,6 +48,24 @@ export class ConfigMigrationService { async migrateConfig(): Promise { this.config = await this.configService.loadConfig(this.entityMapper); + this.addNewConfigurableEnums(); + this.migrateViewConfigs(); + console.log("config", this.config); + return this.configService.saveConfig(this.entityMapper, this.config.data); + } + + private addNewConfigurableEnums() { + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "reading-levels" + ] = readingLevels; + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "math-levels" + ] = mathLevels; + this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "genders"] = genders; + this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "materials"] = materials; + } + + private migrateViewConfigs() { const viewConfigs = this.configService.getAllConfigs("view:"); viewConfigs.forEach((viewConfig) => { const entity = this.getEntity(viewConfig._id); @@ -53,8 +76,6 @@ export class ConfigMigrationService { this.migrateEntityDetailsConfig(viewConfig.config, entity); } }); - console.log("config", this.config); - return this.configService.saveConfig(this.entityMapper, this.config.data); } private getEntity(viewId: string): EntityConstructor { diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts new file mode 100644 index 0000000000..363a916459 --- /dev/null +++ b/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts @@ -0,0 +1,80 @@ +import { TestBed } from "@angular/core/testing"; + +import { ConfigurableEnumMigrationService } from "./configurable-enum-migration.service"; +import { PouchDatabase } from "../database/pouch-database"; +import { EntityMapperService } from "../entity/entity-mapper.service"; +import { EntitySchemaService } from "../entity/schema/entity-schema.service"; +import { Database } from "../database/database"; +import { ConfigurableEnumModule } from "./configurable-enum.module"; + +describe("ConfigurableEnumMigrationService", () => { + let service: ConfigurableEnumMigrationService; + let database: PouchDatabase; + + beforeEach(() => { + database = PouchDatabase.createWithInMemoryDB(); + TestBed.configureTestingModule({ + imports: [ConfigurableEnumModule], + providers: [ + EntityMapperService, + EntitySchemaService, + { provide: Database, useValue: database }, + ], + }); + service = TestBed.inject(ConfigurableEnumMigrationService); + }); + + afterEach(async () => { + await database.destroy(); + }); + + it("should be created", () => { + expect(service).toBeTruthy(); + }); + + it("should migrate aser entities", async () => { + const oldAser = { + _id: "Aser:1", + child: "childId", + date: new Date(), + hindi: "Nothing", + bengali: "Read Letters", + english: "Read Words", + math: "Numbers 1-9", + remarks: "some remarks", + }; + await database.put(oldAser); + + await service.migrateSelectionsToConfigurableEnum(); + const newAser = await database.get("Aser:1"); + + expect(newAser["child"]).toBe(oldAser.child); + expect(newAser["hindi"]).toBe("nothing"); + expect(newAser["bengali"]).toBe("read_letters"); + expect(newAser["english"]).toBe("read_words"); + expect(newAser["math"]).toBe("numbers1to9"); + expect(new Date(newAser["date"])).toEqual(oldAser.date); + expect(newAser["remarks"]).toBe(oldAser.remarks); + }); + + it("should migrate education material entities", async () => { + const oldMaterial = { + _id: "EducationalMaterial:1", + child: "childId", + date: new Date(), + materialType: "pen (black)", + materialAmount: 2, + description: "some description", + }; + await database.put(oldMaterial); + + await service.migrateSelectionsToConfigurableEnum(); + const newMaterial = await database.get("EducationalMaterial:1"); + + expect(newMaterial["child"]).toBe(oldMaterial.child); + expect(new Date(newMaterial["date"])).toEqual(oldMaterial.date); + expect(newMaterial["materialType"]).toBe("pen_black"); + expect(newMaterial["materialAmount"]).toBe(oldMaterial.materialAmount); + expect(newMaterial["description"]).toBe(oldMaterial.description); + }); +}); diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.ts new file mode 100644 index 0000000000..7f5a81630f --- /dev/null +++ b/src/app/core/configurable-enum/configurable-enum-migration.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from "@angular/core"; +import { EntityMapperService } from "../entity/entity-mapper.service"; +import { EducationalMaterial } from "../../child-dev-project/educational-material/model/educational-material"; +import { Aser } from "../../child-dev-project/aser/model/aser"; +import { Entity } from "../entity/entity"; + +@Injectable({ + providedIn: "root", +}) +export class ConfigurableEnumMigrationService { + constructor(private entityMapper: EntityMapperService) {} + + async migrateSelectionsToConfigurableEnum(): Promise { + const entitiesToMigrate: typeof Entity[] = [Aser, EducationalMaterial]; + for (const entityConstructor of entitiesToMigrate) { + const entities = await this.entityMapper.loadType(entityConstructor); + // The entities will automatically be saved correctly once the schema is applied + await Promise.all( + entities.map((entity) => this.entityMapper.save(entity)) + ); + } + } +} From f66e367bd41f551bdfb89df884e3de16898bc8b8 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 24 Jun 2021 17:22:31 +0200 Subject: [PATCH 184/230] made warning level configurable enum --- .../aser/demo-aser-generator.service.ts | 5 ++- .../child-dev-project/aser/model/aser.spec.ts | 10 +++-- src/app/child-dev-project/aser/model/aser.ts | 8 ++-- .../attendance/model/activity-attendance.ts | 13 +++--- .../attendance/model/attendance-month.spec.ts | 6 ++- .../attendance/model/attendance-month.ts | 11 ++--- .../children-bmi-dashboard.component.ts | 7 ++-- .../model/educational-material.ts | 5 +-- .../health-checkup/model/health-check.ts | 11 ++--- .../demo-data/demo-note-generator.service.ts | 4 +- .../notes/demo-data/notes_group-stories.ts | 12 +++--- .../demo-data/notes_individual-stories.ts | 26 ++++++------ .../notes/model/note.spec.ts | 13 +++--- src/app/child-dev-project/notes/model/note.ts | 26 ++++-------- .../notes-manager/notes-manager.component.ts | 15 +++++-- src/app/child-dev-project/warning-level.ts | 41 +++++++++++-------- src/app/core/config/config-fix.ts | 2 + .../configurable-enum.interface.ts | 5 +++ src/app/core/entity/entity.ts | 12 +++--- 19 files changed, 126 insertions(+), 106 deletions(-) diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index 80dfe239e5..ad30b63c02 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -3,7 +3,7 @@ import { DemoDataGenerator } from "../../core/demo-data/demo-data-generator"; import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; -import { WarningLevel } from "../warning-level"; +import { warningLevels } from "../warning-level"; import { Aser } from "./model/aser"; import { ConfigurableEnumValue } from "../../core/configurable-enum/configurable-enum.interface"; import { mathLevels } from "./model/mathLevels"; @@ -68,7 +68,8 @@ export class DemoAserGeneratorService extends DemoDataGenerator { previousResult = aserResult; } while ( date < faker.getEarlierDateOrToday(child.dropoutDate) && - previousResult.getWarningLevel() !== WarningLevel.OK + previousResult.getWarningLevel() !== + warningLevels.find((level) => level.id === "OK") ); return data; diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index 10f8f65eec..cc19e06c9b 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -16,7 +16,7 @@ */ import { Aser } from "./aser"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; @@ -79,7 +79,9 @@ describe("Aser", () => { const id = "test1"; const entity = new Aser(id); - expect(entity.getWarningLevel()).toBe(WarningLevel.OK); + expect(entity.getWarningLevel()).toBe( + warningLevels.find((level) => level.id === "OK") + ); }); it("warning level WARNING if some bad results", function () { @@ -88,6 +90,8 @@ describe("Aser", () => { entity.english = readingLevels[1]; entity.math = readingLevels[2]; - expect(entity.getWarningLevel()).toBe(WarningLevel.WARNING); + expect(entity.getWarningLevel()).toBe( + warningLevels.find((level) => level.id === "WARNING") + ); }); }); diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index 66a37250b7..661e0086f3 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -16,7 +16,7 @@ */ import { Entity } from "../../../core/entity/entity"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; @@ -70,7 +70,7 @@ export class Aser extends Entity { math: ConfigurableEnumValue; @DatabaseField({ label: "Remarks" }) remarks: string = ""; - getWarningLevel(): WarningLevel { + getWarningLevel(): ConfigurableEnumValue { let warningLevel; if ( @@ -79,9 +79,9 @@ export class Aser extends Entity { Aser.isReadingPassedOrNA(this.bengali) && Aser.isMathPassedOrNA(this.math) ) { - warningLevel = WarningLevel.OK; + warningLevel = warningLevels.find((level) => level.id === "OK"); } else { - warningLevel = WarningLevel.WARNING; + warningLevel = warningLevels.find((level) => level.id === "WARNING"); } return warningLevel; diff --git a/src/app/child-dev-project/attendance/model/activity-attendance.ts b/src/app/child-dev-project/attendance/model/activity-attendance.ts index 2a1cb15c5d..bfeeaf9709 100644 --- a/src/app/child-dev-project/attendance/model/activity-attendance.ts +++ b/src/app/child-dev-project/attendance/model/activity-attendance.ts @@ -5,8 +5,9 @@ import { import { Entity } from "../../../core/entity/entity"; import { RecurringActivity } from "./recurring-activity"; import { defaultAttendanceStatusTypes } from "../../../core/config/default-config/default-attendance-status-types"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { EventNote } from "./event-note"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; /** * Aggregate information about all events for a {@link RecurringActivity} within a given time period. @@ -198,7 +199,7 @@ export class ActivityAttendance extends Entity { /** * Custom warning level for attendance thresholds - optionally for a specific child. */ - public getWarningLevel(forChildId?: string): WarningLevel { + public getWarningLevel(forChildId?: string): ConfigurableEnumValue { let attendancePercentage; if (forChildId) { attendancePercentage = this.getAttendancePercentage(forChildId); @@ -207,13 +208,13 @@ export class ActivityAttendance extends Entity { } if (!attendancePercentage) { - return WarningLevel.NONE; + return warningLevels.find((level) => level.id === "OK"); } else if (attendancePercentage < ActivityAttendance.THRESHOLD_URGENT) { - return WarningLevel.URGENT; + return warningLevels.find((level) => level.id === "URGENT"); } else if (attendancePercentage < ActivityAttendance.THRESHOLD_WARNING) { - return WarningLevel.WARNING; + return warningLevels.find((level) => level.id === "WARNING"); } else { - return WarningLevel.OK; + return warningLevels.find((level) => level.id === "OK"); } } } diff --git a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts index cf2b3298e8..3e61ced23d 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts @@ -16,7 +16,7 @@ */ import { AttendanceMonth, daysInMonth } from "./attendance-month"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; @@ -103,7 +103,9 @@ describe("AttendanceMonth", () => { entity.daysWorking = working; entity.daysAttended = attended; - expect(entity.getWarningLevel()).toBe(WarningLevel.URGENT); + expect(entity.getWarningLevel()).toBe( + warningLevels.find((level) => level.id === "URGENT") + ); }); it("has dailyRegister array after creation", () => { diff --git a/src/app/child-dev-project/attendance/model/attendance-month.ts b/src/app/child-dev-project/attendance/model/attendance-month.ts index 96a7618e0a..b326ca8551 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.ts @@ -16,11 +16,12 @@ */ import { Entity } from "../../../core/entity/entity"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { AttendanceDay } from "./attendance-day"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { AttendanceStatus } from "./attendance-status"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; /** * @deprecated Use new system based on EventNote and RecurrentActivity instead @@ -222,14 +223,14 @@ export class AttendanceMonth extends Entity { return this.daysAttended / (this.daysWorking - this.daysExcused); } - getWarningLevel() { + getWarningLevel(): ConfigurableEnumValue { const attendance = this.getAttendancePercentage(); if (attendance < AttendanceMonth.THRESHOLD_URGENT) { - return WarningLevel.URGENT; + return warningLevels.find((level) => level.id === "URGENT"); } else if (attendance < AttendanceMonth.THRESHOLD_WARNING) { - return WarningLevel.WARNING; + return warningLevels.find((level) => level.id === "WARNING"); } else { - return WarningLevel.OK; + return warningLevels.find((level) => level.id === "OK"); } } } diff --git a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts index 80c7b4fc58..933941a65b 100644 --- a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts +++ b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { HealthCheck } from "../../health-checkup/model/health-check"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { take } from "rxjs/operators"; import { ChildrenService } from "../children.service"; @@ -46,14 +46,15 @@ export class ChildrenBmiDashboardComponent .getHealthChecksOfChild(child.getId()) .pipe() .subscribe((results) => { - /** get newest HealtCheck */ + /** get latest HealthCheck */ if (results.length > 0) { this.currentHealthCheck = results.reduce((prev, cur) => cur.date > prev.date ? cur : prev ); /**Check health status */ if ( - this.currentHealthCheck.getWarningLevel() === WarningLevel.URGENT + this.currentHealthCheck.getWarningLevel() === + warningLevels.find((level) => level.id === "URGENT") ) { this.bmiRows.push({ childId: child.getId(), diff --git a/src/app/child-dev-project/educational-material/model/educational-material.ts b/src/app/child-dev-project/educational-material/model/educational-material.ts index 05b9848de1..99a1d4f370 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.ts @@ -22,7 +22,6 @@ import { ConfigurableEnumValue } from "../../../core/configurable-enum/configura @DatabaseEntity("EducationalMaterial") export class EducationalMaterial extends Entity { - @DatabaseField() child: string; // id of Child entity @DatabaseField({ label: "Date" }) date: Date; @DatabaseField({ @@ -35,8 +34,6 @@ export class EducationalMaterial extends Entity { @DatabaseField({ label: "Description" }) description = ""; public getColor() { - return this.materialType && this.materialType["color"] - ? this.materialType["color"] - : "white"; + return this.materialType?.color || "white"; } } diff --git a/src/app/child-dev-project/health-checkup/model/health-check.ts b/src/app/child-dev-project/health-checkup/model/health-check.ts index 04ab7bbb6f..e87838a85c 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.ts @@ -18,7 +18,8 @@ import { Entity } from "../../../core/entity/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; /** * Model Class for the Health Checks that are taken for a Child. @@ -49,13 +50,13 @@ export class HealthCheck extends Entity { return this.weight / ((this.height / 100) * (this.height / 100)); } - getWarningLevel() { + getWarningLevel(): ConfigurableEnumValue { if (this.bmi <= 16 || this.bmi >= 30) { - return WarningLevel.URGENT; + return warningLevels.find((level) => level.id === "URGENT"); } else if (this.bmi >= 18 && this.bmi <= 25) { - return WarningLevel.OK; + return warningLevels.find((level) => level.id === "OK"); } else { - return WarningLevel.WARNING; + return warningLevels.find((level) => level.id === "WARNING"); } } } diff --git a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts index da6e309b8e..b1fbbc331d 100644 --- a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts +++ b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts @@ -4,7 +4,7 @@ import { Injectable } from "@angular/core"; import { Child } from "../../children/model/child"; import { Note } from "../model/note"; import { faker } from "../../../core/demo-data/faker"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { noteIndividualStories } from "./notes_individual-stories"; import { noteGroupStories } from "./notes_group-stories"; import { centersUnique } from "../../children/demo-data-generators/fixtures/centers"; @@ -146,7 +146,7 @@ export class DemoNoteGeneratorService extends DemoDataGenerator { const lastMonths = new Date(); lastMonths.setMonth(lastMonths.getMonth() - 1); if (note.date < lastMonths) { - note.warningLevel = WarningLevel.OK; + note.warningLevel = warningLevels.find((level) => level.id === "OK"); } } diff --git a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts index df640c61e3..598447a6e7 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts @@ -1,16 +1,16 @@ -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; export const noteGroupStories = [ { category: "GUARDIAN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Guardians Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "GUARDIAN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Guardians Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", @@ -18,21 +18,21 @@ export const noteGroupStories = [ { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Children Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Children Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Drug Prevention Workshop", text: "Expert conducted a two day workshop on drug prevention.", }, diff --git a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts index 3914ba9849..164a10ce68 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts @@ -1,9 +1,9 @@ -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; export const noteIndividualStories = [ { category: "HOME_VISIT", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Mother sick", text: "Visited family after we heard that mother is seriously ill. She cannot get up. " + @@ -12,7 +12,7 @@ export const noteIndividualStories = [ }, { category: "GUARDIAN_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Discussed school change", text: "Discussed future of the child with the parents. They agree that changing school can be a good option. " + @@ -21,21 +21,21 @@ export const noteIndividualStories = [ { category: "PHONE_CALL", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Follow up for school absence", text: "Called to ask for reason about absence. Mother made excuses but promised to send the child tomorrow.", }, { category: "PHONE_CALL", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Absent because ill", text: "Mother has called in the morning. Child cannot come to class because of fever.", }, { category: "PHONE_CALL", - warningLevel: WarningLevel.URGENT, + warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: "Absence without information", text: "Child was not in school whole last week again. When calling the mother she didn't know about it. " + @@ -44,7 +44,7 @@ export const noteIndividualStories = [ { category: "VISIT", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "School is happy about progress", text: "Visited the school and talked to the class teacher and principal. They are happy about the progress " + @@ -52,7 +52,7 @@ export const noteIndividualStories = [ }, { category: "COACHING_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Needs to work more for school", text: "Discussed the child's progress with coaching teacher. He is still a weak student and needs more support. " + @@ -61,7 +61,7 @@ export const noteIndividualStories = [ { category: "INCIDENT", - warningLevel: WarningLevel.URGENT, + warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: "Fight at school", text: "Principal called us today. Our student got into a fight and was suspended for a week. " + @@ -70,7 +70,7 @@ export const noteIndividualStories = [ { category: "DISCUSSION", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Special help for family", text: "Since the father has lost his job the family is struggling to survive. " + @@ -78,7 +78,7 @@ export const noteIndividualStories = [ }, { category: "DISCUSSION", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Chance to repeat class", text: "Child has failed this school year as she did not go to school regularly. " + @@ -88,7 +88,7 @@ export const noteIndividualStories = [ { category: "CHILD_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Distracted in class", text: "Teacher has let us know that he is very unfocused during class these days. " + @@ -96,7 +96,7 @@ export const noteIndividualStories = [ }, { category: "CHILD_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Disturbing class", text: "She refused to listen to the teacher was disturbing the class. " + diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index 4a5b283a0f..cc908701ad 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -1,5 +1,5 @@ import { Note } from "./note"; -import { WarningLevel, WarningLevelColor } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/entity"; @@ -47,7 +47,7 @@ function createTestModel(): Note { n1.subject = "Note Subject"; n1.text = "Note text"; n1.authors = ["1"]; - n1.warningLevel = WarningLevel.URGENT; + n1.warningLevel = warningLevels.find((level) => level.id === "URGENT"); return n1; } @@ -110,7 +110,7 @@ describe("Note", () => { text: "Note text", authors: ["1"], category: "GUARDIAN_TALK", - warningLevel: WarningLevel.URGENT, + warningLevel: "OK", searchIndices: [], }; @@ -120,6 +120,7 @@ describe("Note", () => { entity.category = testInteractionTypes.find( (c) => c.id === "GUARDIAN_TALK" ); + entity.warningLevel = warningLevels.find((level) => level.id === "OK"); const rawData = entitySchemaService.transformEntityToDatabaseFormat(entity); @@ -159,8 +160,10 @@ describe("Note", () => { const note = new Note("1"); note.category = { id: "", label: "test", color: "#FFFFFF" }; expect(note.getColor()).toBe("#FFFFFF"); - note.warningLevel = WarningLevel.URGENT; - expect(note.getColor()).toBe(WarningLevelColor(WarningLevel.URGENT)); + note.warningLevel = warningLevels.find((level) => level.id === "URGENT"); + expect(note.getColor()).toBe( + warningLevels.find((level) => level.id === "URGENT").color + ); }); it("transforms interactionType from config", function () { diff --git a/src/app/child-dev-project/notes/model/note.ts b/src/app/child-dev-project/notes/model/note.ts index a345ae6aa8..327b8711e5 100644 --- a/src/app/child-dev-project/notes/model/note.ts +++ b/src/app/child-dev-project/notes/model/note.ts @@ -18,7 +18,7 @@ import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { Entity } from "../../../core/entity/entity"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { WarningLevel, WarningLevelColor } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { INTERACTION_TYPE_CONFIG_ID, InteractionType, @@ -30,6 +30,7 @@ import { } from "../../attendance/model/attendance-status"; import { User } from "../../../core/user/user"; import { Child } from "../../children/model/child"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; @DatabaseEntity("Note") export class Note extends Entity { @@ -95,28 +96,19 @@ export class Note extends Entity { @DatabaseField() schools: string[] = []; @DatabaseField({ - dataType: "string", label: "", - editComponent: "EditSelectable", - additional: ["OK", "WARNING", "URGENT"], + dataType: "configurable-enum", + innerDataType: "warning-levels", }) - warningLevel: WarningLevel = WarningLevel.OK; + warningLevel: ConfigurableEnumValue; - getWarningLevel(): WarningLevel { - return this.warningLevel; + getWarningLevel(): ConfigurableEnumValue { + return this.warningLevel || super.getWarningLevel(); } // TODO: color logic should not be part of entity/model but rather in the component responsible for displaying it public getColor() { - if (this.warningLevel === WarningLevel.URGENT) { - return WarningLevelColor(WarningLevel.URGENT); - } - if (this.warningLevel === WarningLevel.WARNING) { - return WarningLevelColor(WarningLevel.WARNING); - } - - const color = this.category.color; - return color ? color : ""; + return super.getColor() || this.category.color || ""; } public getColorForId(childId: string) { @@ -126,7 +118,7 @@ export class Note extends Entity { AttendanceLogicalStatus.ABSENT ) { // child is absent, highlight the entry - return WarningLevelColor(WarningLevel.URGENT); + return warningLevels.find((warning) => warning.id === "URGENT").color; } return this.getColor(); } diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts index 4490f9ef61..cd774aa416 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts @@ -3,7 +3,7 @@ import { Note } from "../model/note"; import { MediaObserver } from "@angular/flex-layout"; import { NoteDetailsComponent } from "../note-details/note-details.component"; import { ActivatedRoute } from "@angular/router"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-level"; import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; import { FilterSelectionOption } from "../../../core/filter/filter-selection/filter-selection"; import { SessionService } from "../../../core/session/session-service/session.service"; @@ -44,18 +44,25 @@ export class NotesManagerComponent implements OnInit { noteConstructor = Note; notes: Note[] = []; + private readonly urgentLevel = warningLevels.find( + (level) => level.id === "URGENT" + ); + private readonly warningLevel = warningLevels.find( + (level) => level.id === "WARNING" + ); + private statusFS: FilterSelectionOption[] = [ { key: "urgent", label: "Urgent", - filterFun: (n: Note) => n.warningLevel === WarningLevel.URGENT, + filterFun: (n: Note) => n.warningLevel === this.urgentLevel, }, { key: "follow-up", label: "Needs Follow-Up", filterFun: (n: Note) => - n.warningLevel === WarningLevel.WARNING || - n.warningLevel === WarningLevel.URGENT, + n.warningLevel === this.warningLevel || + n.warningLevel === this.urgentLevel, }, { key: "", label: "All", filterFun: () => true }, ]; diff --git a/src/app/child-dev-project/warning-level.ts b/src/app/child-dev-project/warning-level.ts index 60a1a0d30f..c319e6db39 100644 --- a/src/app/child-dev-project/warning-level.ts +++ b/src/app/child-dev-project/warning-level.ts @@ -1,19 +1,24 @@ -export enum WarningLevel { - OK = "OK", - WARNING = "WARNING", - URGENT = "URGENT", - NONE = "", -} +import { ConfigurableEnumValue } from "../core/configurable-enum/configurable-enum.interface"; -export function WarningLevelColor(warningLevel: WarningLevel): string { - switch (warningLevel) { - case WarningLevel.OK: - return "#90ee9040"; - case WarningLevel.WARNING: - return "#ffa50080"; - case WarningLevel.URGENT: - return "#fd727280"; - default: - return ""; - } -} +export const warningLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "None", + color: "", + }, + { + id: "OK", + label: "OK", + color: "#90ee9040", + }, + { + id: "WARNING", + label: "WARNING", + color: "#ffa50080", + }, + { + id: "URGENT", + label: "URGENT", + color: "#fd727280", + }, +]; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 3fb5244081..719607f28c 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -8,6 +8,7 @@ import { genders } from "../../child-dev-project/children/model/genders"; import { materials } from "../../child-dev-project/educational-material/model/materials"; import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; +import { warningLevels } from "../../child-dev-project/warning-level"; // prettier-ignore export const defaultJsonConfig = { @@ -83,6 +84,7 @@ export const defaultJsonConfig = { "enum:math-levels": mathLevels, "enum:genders": genders, "enum:materials": materials, + "enum:warning-levels": warningLevels, "enum:document-status": [ { "id": "", diff --git a/src/app/core/configurable-enum/configurable-enum.interface.ts b/src/app/core/configurable-enum/configurable-enum.interface.ts index 83735800af..6ca3054b5b 100644 --- a/src/app/core/configurable-enum/configurable-enum.interface.ts +++ b/src/app/core/configurable-enum/configurable-enum.interface.ts @@ -21,6 +21,11 @@ export interface ConfigurableEnumValue { */ label: string; + /** + * an optional color code which should be displayed + */ + color?: string; + /** * Optionally any number of additional properties specific to a certain enum collection. */ diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/entity.ts index fd2eb3e73e..e8eb65e589 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/entity.ts @@ -18,10 +18,8 @@ import { v4 as uuid } from "uuid"; import { EntitySchema } from "./schema/entity-schema"; import { DatabaseField } from "./database-field.decorator"; -import { - WarningLevel, - WarningLevelColor, -} from "../../child-dev-project/warning-level"; +import { warningLevels } from "../../child-dev-project/warning-level"; +import { ConfigurableEnumValue } from "../configurable-enum/configurable-enum.interface"; /** * This represents a static class of type . @@ -204,15 +202,15 @@ export class Entity { * Override this method as needed. */ public getColor() { - return WarningLevelColor(this.getWarningLevel()); + return this.getWarningLevel().color; } /** * Override getWarningLevel() to define when the entity is in a critical condition and should be color-coded * and highlighted in generic components of the UI. */ - public getWarningLevel(): WarningLevel { - return WarningLevel.NONE; + public getWarningLevel(): ConfigurableEnumValue { + return warningLevels.find((warning) => warning.id === ""); } /** From d4706d270cffee2431a414ff37d52b17ec6d1c23 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 10:21:53 +0200 Subject: [PATCH 185/230] added migration for input select --- .../config/config-migration.service.spec.ts | 72 +++++++++++++++++-- .../core/config/config-migration.service.ts | 52 +++++++++++++- 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index f5e0e63937..5db4349cc7 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -5,8 +5,12 @@ import { ConfigService } from "./config.service"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { Config } from "./config"; import { EntityConfig } from "../entity/entity-config.service"; -import { CONFIGURABLE_ENUM_CONFIG_PREFIX } from "../configurable-enum/configurable-enum.interface"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumValue, +} from "../configurable-enum/configurable-enum.interface"; import { genders } from "../../child-dev-project/children/model/genders"; +import { EntitySchemaField } from "../entity/schema/entity-schema-field"; describe("ConfigMigrationService", () => { let service: ConfigMigrationService; @@ -156,6 +160,12 @@ describe("ConfigMigrationService", () => { placeholder: "Gender", options: ["M", "F"], }, + { + input: "select", + id: "status", + placeholder: "Status", + options: ["Active", "Inactive", "Still Considering"], + }, ], [ { @@ -294,13 +304,28 @@ describe("ConfigMigrationService", () => { const childConfig = configService.getConfig("entity:Child"); const centerSchema = childConfig.attributes.find( (attr) => attr.name === "center" - ); - expect(centerSchema.schema).toEqual(expectedCenterSchema); + ).schema; + expect(centerSchema).toEqual(expectedCenterSchema); }); it("should migrate the details configs", async () => { const childDetailsConfig = configService.getConfig("view:child/:id"); expect(childDetailsConfig).toEqual(expectedChildDetailsConfig); + + const childConfig = configService.getConfig("entity:Child"); + const genderSchema = childConfig.attributes.find( + (attr) => attr.name === "gender" + ).schema; + expect(genderSchema).toEqual(expectedGenderSchema); + + const statusSchema = childConfig.attributes.find( + (attr) => attr.name === "status" + ).schema; + expect(statusSchema).toEqual(expectedStatusSchema); + const statusEnum = configService.getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + "status" + ); + expect(statusEnum).toEqual(expectedStatusConfigurableEnum); }); it("should add configurable enum configs", () => { @@ -398,13 +423,46 @@ const expectedChildrenListConfig = { }, }; -const expectedCenterSchema = { +const expectedCenterSchema: EntitySchemaField = { dataType: "configurable-enum", innerDataType: "center", labelShort: "Center", label: "Center", }; +const expectedGenderSchema: EntitySchemaField = { + dataType: "configurable-enum", + innerDataType: "genders", + label: "Gender", + labelShort: "Gender", +}; + +const expectedStatusSchema: EntitySchemaField = { + dataType: "configurable-enum", + innerDataType: "status", + label: "Status", + labelShort: "Status", +}; + +const expectedStatusConfigurableEnum: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "active", + label: "Active", + }, + { + id: "inactive", + label: "Inactive", + }, + { + id: "still_considering", + label: "Still Considering", + }, +]; + const expectedChildDetailsConfig = { component: "EntityDetails", _id: "view:child/:id", @@ -450,10 +508,12 @@ const expectedChildDetailsConfig = { label: "Date of Birth", }, { - edit: "EditSelectable", id: "gender", label: "Gender", - additional: ["M", "F"], + }, + { + id: "status", + label: "Status", }, ], [ diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 12ace6ac4e..436926a88d 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -27,7 +27,10 @@ import { readingLevels } from "../../child-dev-project/aser/model/readingLevels" import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; import { genders } from "../../child-dev-project/children/model/genders"; import { materials } from "../../child-dev-project/educational-material/model/materials"; -import { CONFIGURABLE_ENUM_CONFIG_PREFIX } from "../configurable-enum/configurable-enum.interface"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumValue, +} from "../configurable-enum/configurable-enum.interface"; @Injectable({ providedIn: "root", @@ -270,7 +273,11 @@ export class ConfigMigrationService { if (formField.id === "photoFile") { formField.id = "photo"; } - formField.edit = editMap.get(formField["input"]); + if (formField["input"] === "select") { + this.migrateSelectFormField(formField, entity); + } else { + formField.edit = editMap.get(formField["input"]); + } delete formField["input"]; this.addLabelToEntity(formField.label, formField.id, entity, "short"); } catch (e) { @@ -280,6 +287,47 @@ export class ConfigMigrationService { ); } + private migrateSelectFormField( + formField: FormFieldConfig, + entity: EntityConstructor + ) { + const selectableMap = new Map([ + ["warningLevel", "warning-levels"], + ["materialType", "materials"], + ["gender", "genders"], + ["hindi", "reading-levels"], + ["bengali", "reading-levels"], + ["english", "reading-levels"], + ["math", "math-levels"], + ]); + if (!selectableMap.has(formField.id)) { + const newEnum: ConfigurableEnumValue[] = [{ id: "", label: "" }].concat( + ...formField["additional"].map((option: string) => { + return { + label: option, + id: option + .toLowerCase() + .replace("(", "") + .replace(")", "") + .replace(" ", "_"), + }; + }) + ); + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + formField.id + ] = newEnum; + console.warn( + `Automatically created enum "${formField.id}" with values:`, + newEnum + ); + selectableMap.set(formField.id, formField.id); + } + const propertySchema = entity.schema.get(formField.id); + propertySchema.dataType = "configurable-enum"; + propertySchema.innerDataType = selectableMap.get(formField.id); + delete formField["additional"]; + } + private migratePreviousSchoolsComponent(columns: FormFieldConfig[]) { if (columns) { columns.forEach((formField) => { From 1b0adbf4ca1d6dcb213d55e1c8f9a8c8e6a59df5 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 10:24:27 +0200 Subject: [PATCH 186/230] removed edit selectable component --- .../core/config/config-migration.service.ts | 1 - .../entity-form/entity-form.stories.ts | 11 ------- .../edit-selectable.component.html | 14 -------- .../edit-selectable.component.scss | 0 .../edit-selectable.component.spec.ts | 33 ------------------- .../edit-selectable.component.ts | 16 --------- .../entity-utils/entity-utils.module.ts | 3 -- src/app/core/view/dynamic-components-map.ts | 2 -- 8 files changed, 80 deletions(-) delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 436926a88d..a808bbf05f 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -253,7 +253,6 @@ export class ConfigMigrationService { ["age", "EditAge"], ["datepicker", "EditDate"], ["entity-select", "EditEntityArray"], - ["select", "EditSelectable"], ]); columns.forEach((row) => row.forEach((formField) => { diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts index 8ed43ba823..aea5be202f 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts @@ -76,17 +76,6 @@ const cols = [ label: "Is active", }, { id: "gender" }, - { - edit: "EditSelectable", - id: "health_vaccinationStatus", - label: "Vaccination Status", - additional: [ - "Good", - "Vaccination Due", - "Needs Checking", - "No Card/Information", - ], - }, ], [ { diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html deleted file mode 100644 index 3be0e10e99..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - {{ label }} - - - - {{ o.label ? o.label : o }} - - - - diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts deleted file mode 100644 index ffcc700f50..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ComponentFixture, TestBed } from "@angular/core/testing"; - -import { EditSelectableComponent } from "./edit-selectable.component"; -import { EntityDetailsModule } from "../../../entity-details/entity-details.module"; -import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { FormControl, FormGroup } from "@angular/forms"; - -describe("EditSelectableComponent", () => { - let component: EditSelectableComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [EntityDetailsModule, NoopAnimationsModule], - declarations: [EditSelectableComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(EditSelectableComponent); - component = fixture.componentInstance; - const formControl = new FormControl(); - const formGroup = new FormGroup({}); - component.formControlName = "testControl"; - component.formControl = formControl; - formGroup.registerControl(component.formControlName, formControl); - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts deleted file mode 100644 index f0b529e9b8..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from "@angular/core"; -import { EditComponent, EditPropertyConfig } from "../edit-component"; - -@Component({ - selector: "app-edit-selectable", - templateUrl: "./edit-selectable.component.html", - styleUrls: ["./edit-selectable.component.scss"], -}) -export class EditSelectableComponent extends EditComponent { - options: (string | { label: string; value: string })[]; - onInitFromDynamicConfig(config: EditPropertyConfig) { - super.onInitFromDynamicConfig(config); - this.options = - config.formFieldConfig.additional || config.propertySchema.additional; - } -} diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index 8fb6e2a2de..c97dac2f90 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -3,7 +3,6 @@ import { CommonModule } from "@angular/common"; import { EditConfigurableEnumComponent } from "./dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./dynamic-form-components/edit-text/edit-text.component"; import { EditDateComponent } from "./dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "./dynamic-form-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "./dynamic-form-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "./dynamic-form-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "./dynamic-form-components/edit-long-text/edit-long-text.component"; @@ -39,7 +38,6 @@ import { MatChipsModule } from "@angular/material/chips"; EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, - EditSelectableComponent, EditAgeComponent, EditBooleanComponent, EditLongTextComponent, @@ -77,7 +75,6 @@ import { MatChipsModule } from "@angular/material/chips"; EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, - EditSelectableComponent, EditAgeComponent, EditBooleanComponent, EditLongTextComponent, diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index c6b9781667..2e9061bb06 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -25,7 +25,6 @@ import { HistoricalDataComponent } from "../../features/historical-data/historic import { EditTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component"; import { EditConfigurableEnumComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditDateComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component"; @@ -71,7 +70,6 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditText", EditTextComponent], ["EditConfigurableEnum", EditConfigurableEnumComponent], ["EditDate", EditDateComponent], - ["EditSelectable", EditSelectableComponent], ["EditEntityArray", EditEntityArrayComponent], ["EditAge", EditAgeComponent], ["EditBoolean", EditBooleanComponent], From d615682118a435bdd4f5879eb6ed42d499493fa1 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 10:25:32 +0200 Subject: [PATCH 187/230] fix wrong selector name --- .../edit-entity-array/edit-entity-array.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts index 5853590e85..251bcc6d99 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts @@ -3,7 +3,7 @@ import { EditComponent, EditPropertyConfig } from "../edit-component"; import { Entity } from "../../../../entity/entity"; @Component({ - selector: "app-edit-selectable-entity", + selector: "app-edit-entity-array", templateUrl: "./edit-entity-array.component.html", styleUrls: ["./edit-entity-array.component.scss"], }) From 7fcf16c3f893fd579e0c32efe2cd6ee24b415842 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 11:00:44 +0200 Subject: [PATCH 188/230] added edit number component --- .../entity-form/entity-form.stories.ts | 4 ++ .../edit-number/edit-number.component.html | 9 ++++ .../edit-number/edit-number.component.scss | 0 .../edit-number/edit-number.component.spec.ts | 50 +++++++++++++++++++ .../edit-number/edit-number.component.ts | 20 ++++++++ .../edit-percentage.component.html | 2 +- .../entity-utils/entity-utils.module.ts | 3 ++ .../schema-datatypes/datatype-number.ts | 2 +- src/app/core/view/dynamic-components-map.ts | 2 + 9 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.scss create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts index aea5be202f..d13b44d79a 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts @@ -65,6 +65,10 @@ const cols = [ id: "name", required: true, }, + { + id: "projectNumber", + edit: "EditNumber", + }, { edit: "EditLongText", id: "additionalInfo", diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html new file mode 100644 index 0000000000..ef8f177907 --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html @@ -0,0 +1,9 @@ + + + + Only numbers are allowed + + + This field is required + + diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts new file mode 100644 index 0000000000..2c0c34d38a --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts @@ -0,0 +1,50 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; + +import { EditNumberComponent } from "./edit-number.component"; +import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatInputModule } from "@angular/material/input"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; + +describe("EditNumberComponent", () => { + let component: EditNumberComponent; + let fixture: ComponentFixture; + let formGroup: FormGroup; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + NoopAnimationsModule, + ], + declarations: [EditNumberComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditNumberComponent); + component = fixture.componentInstance; + const formControl = new FormControl(); + formGroup = new FormGroup({ testProperty: formControl }); + component.onInitFromDynamicConfig({ + formControl: formControl, + propertySchema: {}, + formFieldConfig: { id: "testProperty" }, + }); + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + it("should only allow valid entries", () => { + component.formControl.setValue("one" as any); + expect(formGroup.invalid).toBeTrue(); + + component.formControl.setValue("1" as any); + expect(formGroup.valid).toBeTrue(); + }); +}); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts new file mode 100644 index 0000000000..636a883c8c --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts @@ -0,0 +1,20 @@ +import { Component } from "@angular/core"; +import { EditComponent, EditPropertyConfig } from "../edit-component"; +import { Validators } from "@angular/forms"; + +@Component({ + selector: "app-edit-number", + templateUrl: "./edit-number.component.html", + styleUrls: ["./edit-number.component.scss"], +}) +export class EditNumberComponent extends EditComponent { + onInitFromDynamicConfig(config: EditPropertyConfig) { + super.onInitFromDynamicConfig(config); + const newValidators = [Validators.pattern("[0-9]*")]; + if (this.formControl.validator) { + newValidators.push(this.formControl.validator); + } + this.formControl.setValidators(newValidators); + this.formControl.updateValueAndValidity(); + } +} diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html index 3e301112f4..04eeaba4da 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html @@ -1,7 +1,7 @@ - Only numbers are allowed in this field + Only numbers are allowed Must be equal or smaller 100 (%) diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index c97dac2f90..afe90ce07b 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -32,6 +32,7 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; import { EntitySelectComponent } from "./entity-select/entity-select.component"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatChipsModule } from "@angular/material/chips"; +import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit-number.component"; @NgModule({ declarations: [ @@ -55,6 +56,7 @@ import { MatChipsModule } from "@angular/material/chips"; DisplayPercentageComponent, DisplayUnitComponent, EntitySelectComponent, + EditNumberComponent, ], imports: [ CommonModule, @@ -91,6 +93,7 @@ import { MatChipsModule } from "@angular/material/chips"; ReadonlyFunctionComponent, DisplayPercentageComponent, DisplayUnitComponent, + EditNumberComponent, ], exports: [DisplayEntityComponent, EntitySelectComponent], }) diff --git a/src/app/core/entity/schema-datatypes/datatype-number.ts b/src/app/core/entity/schema-datatypes/datatype-number.ts index 5fe9746861..33a5b6f196 100644 --- a/src/app/core/entity/schema-datatypes/datatype-number.ts +++ b/src/app/core/entity/schema-datatypes/datatype-number.ts @@ -32,7 +32,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const numberEntitySchemaDatatype: EntitySchemaDatatype = { name: "number", viewComponent: "DisplayText", - editComponent: "EditText", + editComponent: "EditNumber", transformToDatabaseFormat: (value) => { return Number(value); diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 2e9061bb06..836691823c 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -39,6 +39,7 @@ import { EditPercentageComponent } from "../entity-components/entity-utils/dynam import { DisplayPercentageComponent } from "../entity-components/entity-utils/view-components/display-percentage/display-percentage.component"; import { DisplayUnitComponent } from "../entity-components/entity-utils/view-components/display-unit/display-unit.component"; import { FormComponent } from "../entity-components/entity-details/form/form.component"; +import { EditNumberComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -82,4 +83,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditPercentage", EditPercentageComponent], ["DisplayPercentage", DisplayPercentageComponent], ["DisplayUnit", DisplayUnitComponent], + ["EditNumber", EditNumberComponent], ]); From 2645317e7d872cd3204a7a6c62e4701c82f279eb Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 13:07:51 +0200 Subject: [PATCH 189/230] added boolean datatype --- src/app/child-dev-project/schools/model/school.ts | 7 +------ .../core/entity/schema-datatypes/datatype-boolean.ts | 12 ++++++++++++ src/app/core/entity/schema/entity-schema.service.ts | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 src/app/core/entity/schema-datatypes/datatype-boolean.ts diff --git a/src/app/child-dev-project/schools/model/school.ts b/src/app/child-dev-project/schools/model/school.ts index 70a9d7a4d8..29ed05745f 100644 --- a/src/app/child-dev-project/schools/model/school.ts +++ b/src/app/child-dev-project/schools/model/school.ts @@ -13,12 +13,7 @@ export class School extends Entity { @DatabaseField({ label: "Medium" }) medium: string = ""; @DatabaseField({ label: "Remarks" }) remarks: string = ""; @DatabaseField({ label: "Website" }) website: string = ""; - @DatabaseField({ - label: "Private School", - editComponent: "EditBoolean", - viewComponent: "DisplayCheckmark", - }) - privateSchool: boolean; + @DatabaseField({ label: "Private School" }) privateSchool: boolean; @DatabaseField({ label: "Contact Number" }) phone: string = ""; @DatabaseField({ label: "Teaching up to class" }) upToClass: number; @DatabaseField({ label: "Board" }) academicBoard: string = ""; diff --git a/src/app/core/entity/schema-datatypes/datatype-boolean.ts b/src/app/core/entity/schema-datatypes/datatype-boolean.ts new file mode 100644 index 0000000000..2062b28379 --- /dev/null +++ b/src/app/core/entity/schema-datatypes/datatype-boolean.ts @@ -0,0 +1,12 @@ +import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; + +export const booleanEntitySchemaDatatype: EntitySchemaDatatype = { + name: "boolean", + editComponent: "EditBoolean", + viewComponent: "DisplayCheckmark", + + transformToDatabaseFormat: (value: boolean) => value, + + transformToObjectFormat: (value) => value, + +} diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index 6d790db117..4e59645456 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -29,6 +29,7 @@ import { arrayEntitySchemaDatatype } from "../schema-datatypes/datatype-array"; import { schemaEmbedEntitySchemaDatatype } from "../schema-datatypes/datatype-schema-embed"; import { dateOnlyEntitySchemaDatatype } from "../schema-datatypes/datatype-date-only"; import { mapEntitySchemaDatatype } from "../schema-datatypes/datatype-map"; +import { booleanEntitySchemaDatatype } from "../schema-datatypes/datatype-boolean"; /** * Transform between entity instances and database objects @@ -63,6 +64,7 @@ export class EntitySchemaService { this.registerSchemaDatatype(arrayEntitySchemaDatatype); this.registerSchemaDatatype(schemaEmbedEntitySchemaDatatype); this.registerSchemaDatatype(mapEntitySchemaDatatype); + this.registerSchemaDatatype(booleanEntitySchemaDatatype); } /** From ce525904d3fc7a43bf6aac8e3705d0f67290c203 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 14:22:20 +0200 Subject: [PATCH 190/230] applied changes according to the review --- src/app/child-dev-project/aser/model/aser.ts | 7 +-- .../attendance/model/recurring-activity.ts | 4 +- .../note-details/note-details.component.html | 6 +- .../configurable-enum.module.ts | 26 ++++++++- ...isplay-configurable-enum.component.spec.ts | 2 +- .../display-configurable-enum.component.ts | 2 +- .../edit-configurable-enum.component.html | 0 .../edit-configurable-enum.component.scss | 0 .../edit-configurable-enum.component.spec.ts | 4 +- .../edit-configurable-enum.component.ts | 4 +- .../entity-details/EntityDetailsConfig.ts | 57 ++++++++++++++++++- .../entity-details.component.spec.ts | 4 +- .../entity-form/entity-form/FormConfig.ts | 57 +++++++++++++++++-- .../entity-list/entity-list.component.ts | 6 +- .../entity-list/filter-component.settings.ts | 28 +++++++++ .../entity-list/filter-generator.service.ts | 8 +-- .../entity-subrecord.component.ts | 16 +++++- .../dynamic-form-components/edit-component.ts | 37 ++++++++++++ .../entity-utils/entity-utils.module.ts | 6 -- .../core/entity/schema/entity-schema-field.ts | 16 ++++++ src/app/core/view/dynamic-components-map.ts | 4 +- 21 files changed, 246 insertions(+), 48 deletions(-) rename src/app/core/{entity-components/entity-utils/view-components => configurable-enum}/display-configurable-enum/display-configurable-enum.component.spec.ts (93%) rename src/app/core/{entity-components/entity-utils/view-components => configurable-enum}/display-configurable-enum/display-configurable-enum.component.ts (73%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.html (100%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.scss (100%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.spec.ts (89%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.ts (72%) create mode 100644 src/app/core/entity-components/entity-list/filter-component.settings.ts diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index 661e0086f3..fe5c0b9cdc 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -30,7 +30,7 @@ export class Aser extends Entity { // not applicable return true; } - return level === readingLevels[5]; + return level === readingLevels.find((it) => it.id === "read_paragraph"); } static isMathPassedOrNA(level: ConfigurableEnumValue) { @@ -38,12 +38,11 @@ export class Aser extends Entity { // not applicable return true; } - return level === mathLevels[5]; + return level === mathLevels.find((it) => it.id === "division"); } @DatabaseField() child: string; // id of Child entity - @DatabaseField({ label: "Date" }) - date: Date = new Date(); + @DatabaseField({ label: "Date" }) date: Date = new Date(); @DatabaseField({ label: "Hindi", dataType: "configurable-enum", diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.ts b/src/app/child-dev-project/attendance/model/recurring-activity.ts index 324307ea8a..68d5e2aaaa 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.ts @@ -69,7 +69,7 @@ export class RecurringActivity extends Entity { /** IDs of groups (schools, teams) whose (active) members should be included in the activity*/ @DatabaseField({ - label: "Schools", + label: "Groups", viewComponent: "DisplayEntityArray", editComponent: "EditEntityArray", additional: School.ENTITY_TYPE, @@ -78,7 +78,7 @@ export class RecurringActivity extends Entity { /** IDs of the users who are responsible for conducting this activity */ @DatabaseField({ - label: "Assigned to", + label: "Assigned user(s)", viewComponent: "DisplayEntityArray", editComponent: "EditEntityArray", additional: User.ENTITY_TYPE, diff --git a/src/app/child-dev-project/notes/note-details/note-details.component.html b/src/app/child-dev-project/notes/note-details/note-details.component.html index 2f9d2839f2..e4424a4123 100644 --- a/src/app/child-dev-project/notes/note-details/note-details.component.html +++ b/src/app/child-dev-project/notes/note-details/note-details.component.html @@ -76,7 +76,7 @@

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}
{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}
{ let component: DisplayConfigurableEnumComponent; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts similarity index 73% rename from src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts rename to src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts index 8e8cd17f0a..1ee172540c 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts +++ b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { ViewComponent } from "../view-component"; +import { ViewComponent } from "../../entity-components/entity-utils/view-components/view-component"; /** * This component displays a text attribute. diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.html diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.scss diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts similarity index 89% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts index 72e17049c8..38b761ea49 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts +++ b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts @@ -1,10 +1,10 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { EditConfigurableEnumComponent } from "./edit-configurable-enum.component"; -import { EntityDetailsModule } from "../../../entity-details/entity-details.module"; +import { EntityDetailsModule } from "../../entity-components/entity-details/entity-details.module"; import { FormControl, FormGroup } from "@angular/forms"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { ConfigService } from "../../../../config/config.service"; +import { ConfigService } from "../../config/config.service"; describe("EditConfigurableEnumComponent", () => { let component: EditConfigurableEnumComponent; diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts similarity index 72% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts index 85431f66bf..a56a08c246 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,6 +1,6 @@ import { Component } from "@angular/core"; -import { EditComponent, EditPropertyConfig } from "../edit-component"; -import { ConfigurableEnumValue } from "../../../../configurable-enum/configurable-enum.interface"; +import { EditComponent, EditPropertyConfig } from "../../entity-components/entity-utils/dynamic-form-components/edit-component"; +import { ConfigurableEnumValue } from "../configurable-enum.interface"; @Component({ selector: "app-edit-configurable-enum", diff --git a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts index e107a813bf..f5120240f4 100644 --- a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts +++ b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts @@ -1,24 +1,79 @@ import { Entity } from "../../entity/entity"; +/** + * The configuration for a entity details page + */ export interface EntityDetailsConfig { + /** + * The name of an icon which should be displayed next to the entity name. + * The name has to be a valid font-awesome icon name. + */ icon: string; + + /** + * The name of the entity (according to the ENTITY_TYPE). + */ entity: string; + + /** + * The configuration for the panels on this details page. + */ panels: Panel[]; } +/** + * A panel is a simple accordion that can be expanded and closed. + * It can hold multiple components. + */ export interface Panel { + /** + * The title of this panel. This should group the contained components. + */ title: string; + + /** + * The configurations for the components in this panel. + */ components: PanelComponent[]; } +/** + * The configuration for a component displayed inside a panel. + */ export interface PanelComponent { + /** + * An optional second title for only this component. + */ title: string; + + /** + * The name of the component according to the DYNAMIC_COMPONENT_MAP. + */ component: string; - config?: PanelConfig; + + /** + * A addition config which will be passed to the component. + */ + config?: any; } +/** + * This interface represents the config which will be created by the entity-details component and passed to each of + * the panel components. + */ export interface PanelConfig { + /** + * The full entity which is displayed in this details page. + */ entity: Entity; + + /** + * Whether this entity has been newly created. + */ creatingNew?: boolean; + + /** + * An additional config which has been defined in the PanelComponent. + */ config?: any; } diff --git a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts index e9b9746894..5ca121ed6c 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts @@ -11,7 +11,7 @@ import { MatNativeDateModule } from "@angular/material/core"; import { ActivatedRoute, Router } from "@angular/router"; import { RouterTestingModule } from "@angular/router/testing"; import { MatSnackBar } from "@angular/material/snack-bar"; -import { PanelConfig } from "./EntityDetailsConfig"; +import { EntityDetailsConfig, PanelConfig } from "./EntityDetailsConfig"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { User } from "../../user/user"; import { SessionService } from "../../session/session-service/session.service"; @@ -27,7 +27,7 @@ describe("EntityDetailsComponent", () => { let routeObserver: Subscriber; - const routeConfig = { + const routeConfig: EntityDetailsConfig = { icon: "child", entity: "Child", panels: [ diff --git a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts index 7699326264..6a5d95a8a5 100644 --- a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts +++ b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts @@ -1,13 +1,32 @@ +/** + * The general configuration for fields in tables and forms. + * This defines which property is displayed on how it should be displayed. + * Most information does not need to be provided if a property with schema definitions is displayed. + */ export interface FormFieldConfig { - view?: string; - - edit?: string; - /** * The id of the entity which should be accessed */ id: string; + /** + * Defines the component that should display this form field. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the component specified in the schema for this property or the default component of the + * property's datatype will be used. + */ + view?: string; + + /** + * Defines the component which allows to edit this form field. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the component specified in the schema for this property or the default component of the + * property's datatype will be used. If nothing is found, the form field will be displayed in the "view" mode. + */ + edit?: string; + /** * A label or description of the expected input */ @@ -19,13 +38,39 @@ export interface FormFieldConfig { */ required?: boolean; + /** + * An additional description which explains this form field. + * + * If nothing is specified, the property schemas "description" field will be used. + */ tooltip?: string; - forTable?: boolean; - + /** + * When set to true, the sorting of this column will be disabled. + * Should be used when the sorting will not work correctly/does not make sense. + * E.g. when displaying a list of entities + */ noSorting?: boolean; + /** + * Further information for the final view/edit component. + * This is necessary when displaying columns where no schema is available, e.g. to display "readonly-functions". + * This should only be used in cases where a property without schema information is displayed. + */ additional?: any; + /** + * visibleFrom The minimal screen size where the column is shown. + * screen size classes: xs 'screen and (max-width: 599px)' + * sm 'screen and (min-width: 600px) and (max-width: 959px)' + * md 'screen and (min-width: 960px) and (max-width: 1279px)' + * lg 'screen and (min-width: 1280px) and (max-width: 1919px)' + * xl 'screen and (min-width: 1920px) and (max-width: 5000px)' + */ visibleFrom?: string; + + /** + * A internal flag that will be automatically set in the entity subrecord in order to adapt the view/edit components. + */ + forTable?: boolean; } diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 42a5d0f9df..aa32f00065 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -20,10 +20,8 @@ import { Entity, EntityConstructor } from "../../entity/entity"; import { OperationType } from "../../permissions/entity-permissions.service"; import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; -import { - FilterComponentSettings, - FilterGeneratorService, -} from "./filter-generator.service"; +import { FilterGeneratorService } from "./filter-generator.service"; +import { FilterComponentSettings } from "./filter-component.settings"; /** * This component allows to create a full blown table with pagination, filtering, searching and grouping. diff --git a/src/app/core/entity-components/entity-list/filter-component.settings.ts b/src/app/core/entity-components/entity-list/filter-component.settings.ts new file mode 100644 index 0000000000..22e3b68ecd --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-component.settings.ts @@ -0,0 +1,28 @@ +import { FilterSelection } from "../../filter/filter-selection/filter-selection"; + +/** + * A simple interface which holds all required information to display and use a filter. + */ +export interface FilterComponentSettings { + /** + * The filter selection which handles the logic for filtering the data. + */ + filterSettings: FilterSelection; + + /** + * The selected option of this filter. + */ + selectedOption?: string; + + /** + * The way in which the filter should be displayed. + * Possible values: "dropdown" which will render it as a dropdown selection. + * Default to buttons next to each other. + */ + display?: string; + + /** + * The label for this filter. + */ + label?: string; +} diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index bc87a69d95..5a3099c100 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -18,13 +18,7 @@ import { ConfigService } from "../../config/config.service"; import { LoggingService } from "../../logging/logging.service"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaField } from "../../entity/schema/entity-schema-field"; - -export interface FilterComponentSettings { - filterSettings: FilterSelection; - selectedOption?: string; - display?: string; - label?: string; -} +import { FilterComponentSettings } from "./filter-component.settings"; @Injectable({ providedIn: "root", diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index db6e0fa67f..0a470bb33d 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -22,6 +22,7 @@ import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { EntityFormService } from "../../entity-form/entity-form.service"; import { MatDialog } from "@angular/material/dialog"; import { EntityFormComponent } from "../../entity-form/entity-form/entity-form.component"; +import { LoggingService } from "../../../logging/logging.service"; export interface TableRow { record: T; @@ -77,6 +78,9 @@ export class EntitySubrecordComponent implements OnChanges { */ @Input() newRecordFactory: () => T; + /** + * Whether the rows of the table are inline editable and new entries can be created through the "+" button. + */ @Input() editable: boolean = true; /** columns displayed in the template's table */ @@ -99,7 +103,8 @@ export class EntitySubrecordComponent implements OnChanges { private alertService: AlertService, private media: MediaObserver, private entityFormService: EntityFormService, - private dialog: MatDialog + private dialog: MatDialog, + private loggingService: LoggingService ) { this.mediaSubscription = this.media .asObservable() @@ -112,10 +117,15 @@ export class EntitySubrecordComponent implements OnChanges { }); } + /** + * A function which should be executed when a row is clicked or a new entity created. + * @param entity The newly created or clicked entity. + * @param creatingNew If a new entity is created, this value is true. + */ @Input() showEntity = (entity: Entity, creatingNew = false) => this.showEntityInForm(entity, creatingNew); - /** function returns the background color for each entry*/ + /** function returns the background color for each row*/ @Input() getBackgroundColor?: (rec: T) => string = (rec: T) => rec.getColor(); /** @@ -149,7 +159,7 @@ export class EntitySubrecordComponent implements OnChanges { true ); } catch (err) { - this.alertService.addWarning(`Error creating form definitions: ${err}`); + this.loggingService.warn(`Error creating form definitions: ${err}`); } } this.recordsDataSource.data = this.records.map((rec) => { diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts index cd8a0bb50d..4c50b498b0 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts @@ -3,12 +3,30 @@ import { AbstractControl, FormControl } from "@angular/forms"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { EntitySchemaField } from "../../../entity/schema/entity-schema-field"; +/** + * The interface for the configuration which is created by the form- or the entity-subrecord-component. + */ export interface EditPropertyConfig { + /** + * The configuration for this form field. + */ formFieldConfig: FormFieldConfig; + + /** + * If available, the schema for the property which is displayed in this field. + */ propertySchema: EntitySchemaField; + + /** + * The form control for this field which is part of a form group of the table/form component. + */ formControl: AbstractControl; } +/** + * A simple extension of the Form control which allows to access the form type-safe. + * refers to the type of the value which is managed in this control. + */ export class TypedFormControl extends FormControl { value: T; setValue( @@ -24,10 +42,29 @@ export class TypedFormControl extends FormControl { } } +/** + * A simple helper class which sets up all the required information for edit-components. + * refers to the type of the value which is processed in the component. + */ export abstract class EditComponent implements OnInitDynamicComponent { + /** + * The tooltip to be displayed. + */ tooltip: string; + + /** + * The name of the form control. + */ formControlName: string; + + /** + * A label for this component. + */ label: string; + + /** + * The typed form control. + */ formControl: TypedFormControl; onInitFromDynamicConfig(config: EditPropertyConfig) { diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index afe90ce07b..f0b93d6d4c 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; -import { EditConfigurableEnumComponent } from "./dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./dynamic-form-components/edit-text/edit-text.component"; import { EditDateComponent } from "./dynamic-form-components/edit-date/edit-date.component"; import { EditAgeComponent } from "./dynamic-form-components/edit-age/edit-age.component"; @@ -14,7 +13,6 @@ import { DisplayEntityComponent } from "./view-components/display-entity/display import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; @@ -36,7 +34,6 @@ import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit- @NgModule({ declarations: [ - EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, EditAgeComponent, @@ -50,7 +47,6 @@ import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit- DisplayEntityArrayComponent, DisplayTextComponent, DisplayDateComponent, - DisplayConfigurableEnumComponent, DisplayCheckmarkComponent, ReadonlyFunctionComponent, DisplayPercentageComponent, @@ -74,7 +70,6 @@ import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit- MatChipsModule, ], entryComponents: [ - EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, EditAgeComponent, @@ -88,7 +83,6 @@ import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit- DisplayEntityArrayComponent, DisplayTextComponent, DisplayDateComponent, - DisplayConfigurableEnumComponent, DisplayCheckmarkComponent, ReadonlyFunctionComponent, DisplayPercentageComponent, diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index 8d6fc0cb74..55eea9c2ea 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -67,6 +67,12 @@ export interface EntitySchemaField { */ viewComponent?: string; + /** + * (Optional) Define using which component this property should be editable in lists and forms. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the default component for this datatype will be used. + */ editComponent?: string; /** @@ -74,9 +80,19 @@ export interface EntitySchemaField { */ label?: string; + /** + * A short label which can be used in tables. + * If nothing is specified, the long name will be used. + */ labelShort?: string; + /** + * A further description of the property which can be displayed in tooltips. + */ description?: string; + /** + * If set to true, the entity cannot be saved without setting a value for this property. + */ required?: boolean; } diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index 836691823c..d6070cfcda 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -15,7 +15,7 @@ import { ChildBlockComponent } from "../../child-dev-project/children/child-bloc import { DisplayTextComponent } from "../entity-components/entity-utils/view-components/display-text/display-text.component"; import { DisplayCheckmarkComponent } from "../entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component"; import { DisplayDateComponent } from "../entity-components/entity-utils/view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayConfigurableEnumComponent } from "../configurable-enum/display-configurable-enum/display-configurable-enum.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "../../child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component"; @@ -23,7 +23,7 @@ import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/d import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; import { EditTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component"; -import { EditConfigurableEnumComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditConfigurableEnumComponent } from "../configurable-enum/edit-configurable-enum/edit-configurable-enum.component"; import { EditDateComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component"; import { EditAgeComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component"; From 8877d6323d383449ad7689accc28a63703619949 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 15:11:37 +0200 Subject: [PATCH 191/230] cleaned up display entity array component --- .../aser/demo-aser-generator.service.ts | 6 ++--- .../entity-subrecord.component.spec.ts | 9 ++++---- .../display-entity-array.component.html | 4 ++-- .../display-entity-array.component.spec.ts | 2 ++ .../display-entity-array.component.ts | 23 +++++++++++-------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index ad30b63c02..2790c1e57f 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -50,15 +50,15 @@ export class DemoAserGeneratorService extends DemoDataGenerator { aserResult.child = child.getId(); aserResult.date = date; aserResult.math = this.selectNextSkillLevel( - mathLevels, + mathLevels.slice(1), previousResult.math ); aserResult.english = this.selectNextSkillLevel( - readingLevels, + readingLevels.slice(1), previousResult.english ); aserResult[firstLanguage] = this.selectNextSkillLevel( - readingLevels, + readingLevels.slice(1), previousResult[firstLanguage] ); diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index c17d4a1472..2366ddc6bc 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -29,6 +29,7 @@ import { Subject } from "rxjs"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { MatSnackBar } from "@angular/material/snack-bar"; import { genders } from "../../../../child-dev-project/children/model/genders"; +import { LoggingService } from "../../../logging/logging.service"; describe("EntitySubrecordComponent", () => { let component: EntitySubrecordComponent; @@ -209,9 +210,9 @@ describe("EntitySubrecordComponent", () => { expect(sortedIds).toEqual(["0", "3", "1", "2"]); }); - it("should log an error when the column definition can not be initialized", () => { - const alertService = TestBed.inject(AlertService); - spyOn(alertService, "addWarning"); + it("should log a warning when the column definition can not be initialized", () => { + const loggingService = TestBed.inject(LoggingService); + spyOn(loggingService, "warn"); component.records = [new Child()]; component.columns = [ { @@ -224,7 +225,7 @@ describe("EntitySubrecordComponent", () => { component.ngOnChanges({ columns: null }); - expect(alertService.addWarning).toHaveBeenCalled(); + expect(loggingService.warn).toHaveBeenCalled(); }); it("should trigger an update of the paginator when changing the page size", fakeAsync(() => { diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html index ff5a2971d7..df083b481d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html @@ -1,4 +1,4 @@ - + -{{ entities.length }} in total +{{ entity[property]?.length }} in total diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts index fadb5775a0..db9b184dec 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts @@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { DisplayEntityArrayComponent } from "./display-entity-array.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { Child } from "../../../../../child-dev-project/children/model/child"; +import { Note } from "../../../../../child-dev-project/notes/model/note"; describe("DisplayEntityArrayComponent", () => { let component: DisplayEntityArrayComponent; @@ -21,6 +22,7 @@ describe("DisplayEntityArrayComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(DisplayEntityArrayComponent); component = fixture.componentInstance; + component.onInitFromDynamicConfig({ entity: new Note(), id: "children" }); fixture.detectChanges(); }); diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts index c4e448230b..8fc8bc48b2 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts @@ -11,22 +11,25 @@ import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; styleUrls: ["./display-entity-array.component.scss"], }) export class DisplayEntityArrayComponent extends ViewComponent { - entities: Entity[] = []; + readonly aggregationThreshold = 5; + entities: Entity[]; constructor(private entityMapper: EntityMapperService) { super(); } async onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); - const entityType = this.entity.getSchema().get(this.property).additional; - const entityConstructor = ENTITY_MAP.get(entityType); - if (!entityConstructor) { - throw new Error(`Could not find type ${entityType} in ENTITY_MAP`); - } const entityIds: string[] = this.entity[this.property] || []; - const entityPromises = entityIds.map((entityId) => - this.entityMapper.load(entityConstructor, entityId) - ); - this.entities = await Promise.all(entityPromises); + if (entityIds.length < this.aggregationThreshold) { + const entityType = this.entity.getSchema().get(this.property).additional; + const entityConstructor = ENTITY_MAP.get(entityType); + if (!entityConstructor) { + throw new Error(`Could not find type ${entityType} in ENTITY_MAP`); + } + const entityPromises = entityIds.map((entityId) => + this.entityMapper.load(entityConstructor, entityId) + ); + this.entities = await Promise.all(entityPromises); + } } } From e8a7c789267658ca410e8da98ab8f02c4631c81f Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 25 Jun 2021 22:33:55 +0200 Subject: [PATCH 192/230] added pipe to reduce change detection cycles --- .../health-checkup.stories.ts | 5 +++- .../entity-form/entity-form.service.spec.ts | 11 ++++--- .../entity-form/entity-form.service.ts | 29 +++++++++++-------- .../entity-form/entity-form.component.ts | 2 +- .../entity-subrecord.component.ts | 5 +++- .../entity-utils/entity-utils.module.ts | 2 ++ .../entity-function.pipe.spec.ts | 8 +++++ .../readonly-function/entity-function.pipe.ts | 15 ++++++++++ .../readonly-function.component.html | 2 +- .../readonly-function.component.ts | 3 +- 10 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts create mode 100644 src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts diff --git a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts index 89a2ee2c44..63fdf0566d 100644 --- a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts +++ b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts @@ -30,7 +30,10 @@ export default { imports: [ChildrenModule], declarations: [], providers: [ - { provide: EntityMapperService, useValue: {} }, + { + provide: EntityMapperService, + useValue: { save: () => Promise.resolve() }, + }, { provide: ChildrenService, useValue: { getHealthChecksOfChild: () => of([hc1, hc2, hc3]) }, diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index e3aea80265..a9be8ab062 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -1,4 +1,4 @@ -import { fakeAsync, TestBed, tick } from "@angular/core/testing"; +import { TestBed } from "@angular/core/testing"; import { EntityFormService } from "./entity-form.service"; import { FormBuilder } from "@angular/forms"; @@ -40,13 +40,12 @@ describe("EntityFormService", () => { expect(entity.getId()).toBe("initialId"); }); - it("should update initial entity if saving is successful", fakeAsync(() => { + it("should return updated entity if saving is successful", async () => { const entity = new Entity("initialId"); const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); - service.saveChanges(formGroup, entity); - tick(); + const newEntity = await service.saveChanges(formGroup, entity); - expect(entity.getId()).toBe("newId"); - })); + expect(newEntity.getId()).toBe("newId"); + }); }); diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 3686566d13..320202b3af 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -64,21 +64,23 @@ export class EntityFormService { return this.fb.group(formConfig); } - public saveChanges(form: FormGroup, entity: Entity): Promise { + /** + * This function applies the changes of the formGroup to the entity. + * If the form is invalid or the entity does not pass validation after applying the changes, an error will be thrown. + * In order to not edit the initial entity until the new one is saved, call entity.copy() on the input entity. + * @param form The formGroup holding the changes + * @param entity The entity on which the changes should be applied. Should be a copy. + */ + public saveChanges(form: FormGroup, entity: T): Promise { this.checkFormValidity(form); - const entityConstructor = entity.getConstructor(); - const tmpEntity = entity.copy(); - - this.assignFormValuesToEntity(form, tmpEntity); - tmpEntity.assertValid(); + this.assignFormValuesToEntity(form, entity); + entity.assertValid(); return this.entityMapper - .save(tmpEntity) - .then(() => Object.assign(entity, tmpEntity)) + .save(entity) + .then(() => entity) .catch((err) => { - throw new Error( - `Could not save ${entityConstructor.ENTITY_TYPE}: ${err}` - ); + throw new Error(`Could not save ${entity.getType()}: ${err}`); }); } @@ -104,7 +106,10 @@ export class EntityFormService { private assignFormValuesToEntity(form: FormGroup, entity: Entity) { Object.keys(form.controls).forEach((key) => { - entity[key] = form.get(key).value; + // Trying to set a getter function will throw an error + if (Object.getOwnPropertyDescriptor(entity, key)?.writable) { + entity[key] = form.get(key).value; + } }); } } diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index bca16ee340..77b97a4222 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -49,7 +49,7 @@ export class EntityFormComponent implements OnInit { } async save(): Promise { - await this.entityFormService.saveChanges(this.form, this.entity); + this.entity = await this.entityFormService.saveChanges(this.form, this.entity); this.switchEdit(); this.onSave.emit(this.entity); } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 0a470bb33d..99fad30d42 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -250,7 +250,10 @@ export class EntitySubrecordComponent implements OnChanges { */ async save(row: TableRow) { try { - await this.entityFormService.saveChanges(row.formGroup, row.record); + row.record = await this.entityFormService.saveChanges( + row.formGroup, + row.record.copy() as T + ); row.formGroup.disable(); } catch (err) { this.alertService.addDanger(err.message); diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index f0b93d6d4c..f8e81792dc 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -31,6 +31,7 @@ import { EntitySelectComponent } from "./entity-select/entity-select.component"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatChipsModule } from "@angular/material/chips"; import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit-number.component"; +import { EntityFunctionPipe } from './view-components/readonly-function/entity-function.pipe'; @NgModule({ declarations: [ @@ -53,6 +54,7 @@ import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit- DisplayUnitComponent, EntitySelectComponent, EditNumberComponent, + EntityFunctionPipe, ], imports: [ CommonModule, diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts new file mode 100644 index 0000000000..2f901d93ea --- /dev/null +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts @@ -0,0 +1,8 @@ +import { EntityFunctionPipe } from './entity-function.pipe'; + +describe('EntityFunctionPipe', () => { + it('create an instance', () => { + const pipe = new EntityFunctionPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts new file mode 100644 index 0000000000..276e22dd8d --- /dev/null +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { Entity } from "../../../../entity/entity"; + +@Pipe({ + name: "entityFunction", +}) +/** + * A simple pipe which passes the input entity to the input function. + * This reduces the change detection cycles, because the function is only re-calculated once the entity changed. + */ +export class EntityFunctionPipe implements PipeTransform { + transform(value: Entity, func?: (entity: Entity) => any): any { + return func(value); + } +} diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html index 1ecdf3cae4..fca05ba09d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html @@ -1 +1 @@ -{{ displayFunction(entity) }} +{{ entity | entityFunction: displayFunction }} diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts index 07f2b1883f..fe2d8ca61d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts @@ -1,6 +1,7 @@ import { Component } from "@angular/core"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { ViewComponent } from "../view-component"; +import { Entity } from "../../../../entity/entity"; @Component({ selector: "app-readonly-function", @@ -8,7 +9,7 @@ import { ViewComponent } from "../view-component"; styleUrls: ["./readonly-function.component.scss"], }) export class ReadonlyFunctionComponent extends ViewComponent { - displayFunction: (Entity) => any; + displayFunction: (entity: Entity) => any; onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); this.displayFunction = config.config; From 57971d9be2c00e849d8b11401183790be1aef6a1 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 08:01:24 +0200 Subject: [PATCH 193/230] fixed tests --- .../entity-form/entity-form.service.spec.ts | 5 +---- .../entity-subrecord.component.spec.ts | 13 +++++++------ .../readonly-function.component.spec.ts | 3 ++- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index a9be8ab062..258a45663c 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -31,13 +31,10 @@ describe("EntityFormService", () => { it("should not save invalid entities", () => { const entity = new Entity("initialId"); - const tmpEntity = new Entity(); - spyOn(entity, "copy").and.returnValue(tmpEntity); - spyOn(tmpEntity, "assertValid").and.throwError(new Error()); + spyOn(entity, "assertValid").and.throwError(new Error()); const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); expect(() => service.saveChanges(formGroup, entity)).toThrowError(); - expect(entity.getId()).toBe("initialId"); }); it("should return updated entity if saving is successful", async () => { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 2366ddc6bc..4c6823e0ac 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -252,7 +252,7 @@ describe("EntitySubrecordComponent", () => { expect(formGroup.enabled).toBeTrue(); }); - it("should correctly save changes to a entity", fakeAsync(() => { + it("should correctly save changes to an entity", fakeAsync(() => { mockEntityMapper.save.and.resolveTo(); const fb = TestBed.inject(FormBuilder); const child = new Child(); @@ -261,14 +261,15 @@ describe("EntitySubrecordComponent", () => { name: "New Name", gender: genders[2], }); + const tableRow = { record: child, formGroup: formGroup }; - component.save({ record: child, formGroup: formGroup }); + component.save(tableRow); tick(); expect(mockEntityMapper.save).toHaveBeenCalledWith(child); - expect(child.name).toBe("New Name"); - expect(child.gender).toBe(genders[2]); - expect(formGroup.disabled).toBeTrue(); + expect(tableRow.record.name).toBe("New Name"); + expect(tableRow.record.gender).toBe(genders[2]); + expect(tableRow.formGroup.disabled).toBeTrue(); })); it("should show a error message when saving fails", fakeAsync(() => { @@ -279,7 +280,7 @@ describe("EntitySubrecordComponent", () => { const alertService = TestBed.inject(AlertService); spyOn(alertService, "addDanger"); - component.save({ formGroup: null, record: null }); + component.save({ formGroup: null, record: new Child() }); tick(); expect(alertService.addDanger).toHaveBeenCalledWith("Form invalid"); diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts index b37d525bf1..2d513b65d8 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ReadonlyFunctionComponent } from "./readonly-function.component"; import { Child } from "../../../../../child-dev-project/children/model/child"; +import { EntityFunctionPipe } from "./entity-function.pipe"; describe("ReadonlyFunctionComponent", () => { let component: ReadonlyFunctionComponent; @@ -9,7 +10,7 @@ describe("ReadonlyFunctionComponent", () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ReadonlyFunctionComponent], + declarations: [ReadonlyFunctionComponent, EntityFunctionPipe], }).compileComponents(); }); From 412b9b8cb8d59190ec1e49eb694f1acc0c0c9459 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 11:45:44 +0200 Subject: [PATCH 194/230] fixed error message when no edit component is defined --- .../entity-subrecord/entity-subrecord.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index ea18976112..ade7ca9fb0 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -34,7 +34,7 @@ }" > { snackbarObservable.next(); expect(mockEntityMapper.save).toHaveBeenCalledWith(child, true); expect(component.records).toEqual([child]); + + flush(); })); it("should create new entities and call the show entity function", fakeAsync(() => { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index cb97059a6f..7f1b50fccd 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -14,7 +14,7 @@ import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { Entity } from "../../../entity/entity"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { AlertService } from "../../../alerts/alert.service"; -import { BehaviorSubject, Subscription } from "rxjs"; +import { Subscription } from "rxjs"; import { entityListSortingAccessor } from "../../entity-list/sorting-accessor"; import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; @@ -47,14 +47,6 @@ export interface TableRow { styleUrls: ["./entity-subrecord.component.scss"], }) export class EntitySubrecordComponent implements OnChanges { - /** - * Global state of pagination size for all entity subrecord components. - * - * When the user changes page size in one component the page size is automatically changed for other components also. - * This ensures a consistent UI e.g. for side-by-side subrecord components of multiple attendance record tables. - */ - static paginatorPageSize = new BehaviorSubject(10); - /** data to be displayed */ @Input() records: Array = []; @@ -147,7 +139,7 @@ export class EntitySubrecordComponent implements OnChanges { entity, true ); - this.idForSavingPagination = this.columns + this.idForSavingPagination = this._columns .map((col) => (typeof col === "object" ? col.id : col)) .join(""); } catch (err) { From dd51adaca941c8c51f5fc6bfdc473a65ac807db2 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 12:17:19 +0200 Subject: [PATCH 196/230] fixed prettier --- .../children/model/childSchoolRelation.ts | 26 +++++++++---------- ...-educational-material-generator.service.ts | 2 +- src/app/core/admin/admin/admin.component.ts | 2 +- .../edit-configurable-enum.component.ts | 5 +++- .../entity-form/entity-form.component.ts | 5 +++- .../entity-utils/entity-utils.module.ts | 2 +- .../entity-function.pipe.spec.ts | 6 ++--- .../schema-datatypes/datatype-boolean.ts | 3 +-- 8 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.ts b/src/app/child-dev-project/children/model/childSchoolRelation.ts index 53651a1040..1dbb29b905 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.ts @@ -9,19 +9,6 @@ import { School } from "../../schools/model/school"; */ @DatabaseEntity("ChildSchoolRelation") export class ChildSchoolRelation extends Entity { - assertValid() { - super.assertValid(); - const startLabel = this.getSchema().get("start").label; - const endLabel = this.getSchema().get("end").label; - if (this.end && !this.start) { - throw new Error(`No "${startLabel}" date is set`); - } else if (moment(this.start).isAfter(this.end, "days")) { - throw new Error( - `The "${startLabel}" date is after the "${endLabel}" date` - ); - } - } - @DatabaseField() childId: string; @DatabaseField({ label: "School", @@ -50,4 +37,17 @@ export class ChildSchoolRelation extends Entity { (!this.end || moment(this.end).isAfter(moment(), "day")) ); } + + assertValid() { + super.assertValid(); + const startLabel = this.getSchema().get("start").label; + const endLabel = this.getSchema().get("end").label; + if (this.end && !this.start) { + throw new Error(`No "${startLabel}" date is set`); + } else if (moment(this.start).isAfter(this.end, "days")) { + throw new Error( + `The "${startLabel}" date is after the "${endLabel}" date` + ); + } + } } diff --git a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts index a1a5011fbe..401f91cca8 100644 --- a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts +++ b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts @@ -3,7 +3,7 @@ import { DemoDataGenerator } from "../../core/demo-data/demo-data-generator"; import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; -import { EducationalMaterial} from "./model/educational-material"; +import { EducationalMaterial } from "./model/educational-material"; import { materials } from "./model/materials"; export class DemoEducationMaterialConfig { diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index 76dbbe2228..43a5796819 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -62,7 +62,7 @@ export class AdminComponent implements OnInit { async migrateConfigChanges() { await this.configMigrationService.migrateConfig(); - await this.configurableEnumMigrationSerivice.migrateSelectionsToConfigurableEnum() + await this.configurableEnumMigrationSerivice.migrateSelectionsToConfigurableEnum(); } /** diff --git a/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts index a56a08c246..5b9844b861 100644 --- a/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,5 +1,8 @@ import { Component } from "@angular/core"; -import { EditComponent, EditPropertyConfig } from "../../entity-components/entity-utils/dynamic-form-components/edit-component"; +import { + EditComponent, + EditPropertyConfig, +} from "../../entity-components/entity-utils/dynamic-form-components/edit-component"; import { ConfigurableEnumValue } from "../configurable-enum.interface"; @Component({ diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index 77b97a4222..6fd0f80069 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -49,7 +49,10 @@ export class EntityFormComponent implements OnInit { } async save(): Promise { - this.entity = await this.entityFormService.saveChanges(this.form, this.entity); + this.entity = await this.entityFormService.saveChanges( + this.form, + this.entity + ); this.switchEdit(); this.onSave.emit(this.entity); } diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index f8e81792dc..a49b63d658 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -31,7 +31,7 @@ import { EntitySelectComponent } from "./entity-select/entity-select.component"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatChipsModule } from "@angular/material/chips"; import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit-number.component"; -import { EntityFunctionPipe } from './view-components/readonly-function/entity-function.pipe'; +import { EntityFunctionPipe } from "./view-components/readonly-function/entity-function.pipe"; @NgModule({ declarations: [ diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts index 2f901d93ea..3bb9daf5bd 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts @@ -1,7 +1,7 @@ -import { EntityFunctionPipe } from './entity-function.pipe'; +import { EntityFunctionPipe } from "./entity-function.pipe"; -describe('EntityFunctionPipe', () => { - it('create an instance', () => { +describe("EntityFunctionPipe", () => { + it("create an instance", () => { const pipe = new EntityFunctionPipe(); expect(pipe).toBeTruthy(); }); diff --git a/src/app/core/entity/schema-datatypes/datatype-boolean.ts b/src/app/core/entity/schema-datatypes/datatype-boolean.ts index 2062b28379..8f5227513a 100644 --- a/src/app/core/entity/schema-datatypes/datatype-boolean.ts +++ b/src/app/core/entity/schema-datatypes/datatype-boolean.ts @@ -8,5 +8,4 @@ export const booleanEntitySchemaDatatype: EntitySchemaDatatype = { transformToDatabaseFormat: (value: boolean) => value, transformToObjectFormat: (value) => value, - -} +}; From 6f157cbec5188ba6b508f49d35fde08fa3fefe72 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 13:07:12 +0200 Subject: [PATCH 197/230] fixed property assignment problem --- .../entity-form/entity-form.service.ts | 3 +- .../entity-list/entity-list.component.ts | 29 +++++++++---------- .../entity-subrecord.component.spec.ts | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 320202b3af..85deb2db77 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -107,7 +107,8 @@ export class EntityFormService { private assignFormValuesToEntity(form: FormGroup, entity: Entity) { Object.keys(form.controls).forEach((key) => { // Trying to set a getter function will throw an error - if (Object.getOwnPropertyDescriptor(entity, key)?.writable) { + const propertyDescriptor = Object.getOwnPropertyDescriptor(entity, key); + if (propertyDescriptor === undefined || propertyDescriptor.writable) { entity[key] = form.get(key).value; } }); diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index aa32f00065..31b9896db7 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -87,7 +87,7 @@ export class EntityListComponent ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty("listConfig")) { this.listName = this.listConfig.title; - this.initColumns(); + this.addColumnsFromColumnGroups(); this.initColumnGroups(this.listConfig.columnGroups); this.filtersConfig = this.listConfig.filters || []; this.displayColumnGroup(this.defaultColumnGroup); @@ -99,21 +99,20 @@ export class EntityListComponent this.loadUrlParams(); } - private initColumns() { + private addColumnsFromColumnGroups() { this.columns = this.listConfig.columns || []; - const uniqueColumnIds = new Set(); - this.listConfig?.columnGroups?.groups?.forEach((group) => - group.columns.forEach((column) => uniqueColumnIds.add(column)) - ); - this.columns.push( - ...new Array(...uniqueColumnIds).filter( - (columnId) => - !this.columns.some((column) => - typeof column === "string" - ? column === columnId - : column.id === columnId - ) - ) + this.listConfig.columnGroups?.groups?.forEach((group) => + group.columns + .filter( + (columnId) => + !this.columns.some((column) => + // Check if the column is already defined as object or string + typeof column === "string" + ? column === columnId + : column.id === columnId + ) + ) + .forEach((column) => this.columns.push(column)) ); } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 4c6823e0ac..3cf0f8e3ee 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -266,7 +266,7 @@ describe("EntitySubrecordComponent", () => { component.save(tableRow); tick(); - expect(mockEntityMapper.save).toHaveBeenCalledWith(child); + expect(mockEntityMapper.save).toHaveBeenCalledWith(tableRow.record); expect(tableRow.record.name).toBe("New Name"); expect(tableRow.record.gender).toBe(genders[2]); expect(tableRow.formGroup.disabled).toBeTrue(); From ff74a0e14b1fbce05fc54487a95531c1a1933f41 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 13:25:49 +0200 Subject: [PATCH 198/230] added further documentation --- .../entity-details.component.ts | 4 +-- .../entity-details/form/form.component.ts | 17 +++++++---- .../entity-form/entity-form.component.ts | 29 +++++++++++++++++-- .../entity-subrecord.component.ts | 2 +- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/app/core/entity-components/entity-details/entity-details.component.ts b/src/app/core/entity-components/entity-details/entity-details.component.ts index 99b60b3410..4b5f4217df 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.ts @@ -38,8 +38,8 @@ export const ENTITY_MAP: Map> = new Map< /** * This component can be used to display a entity in more detail. * It groups subcomponents in panels. - * Any component can be used as a subcomponent. - * The subcomponents will be provided with the Entity object and the creating new status, as well as its static config. + * Any component from the DYNAMIC_COMPONENT_MAP can be used as a subcomponent. + * The subcomponents will be provided with the Entity object and the creating new status, as well as it's static config. */ @Component({ selector: "app-entity-details", diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 74b123d187..bc2d69986f 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -8,13 +8,18 @@ import { Router } from "@angular/router"; @Component({ selector: "app-form", - template: ``, + template: ` + `, }) +/** + * A simple wrapper function of the EntityFormComponent which can be used as a dynamic component + * e.g. as a panel for the EntityDetailsComponent. + */ export class FormComponent implements OnInitDynamicComponent { entity: Entity; columns: FormFieldConfig[][] = []; diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index 6fd0f80069..d666a0bbea 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -10,9 +10,31 @@ import { EntityFormService } from "../entity-form.service"; templateUrl: "./entity-form.component.html", styleUrls: ["./entity-form.component.scss"], }) +/** + * A general purpose form component for displaying and editing entities. + * It uses the FormFieldConfig interface for building the form fields but missing information are also fetched from + * the entity's schema definitions. Properties with sufficient schema information can be displayed by only providing + * the name of this property (and not an FormFieldConfig object). + * + * This component can be used directly or in a popup. + * Inside the entity details component use the FormComponent which is part of the DYNAMIC_COMPONENT_MAP. + */ export class EntityFormComponent implements OnInit { + /** + * The entity which should be displayed and edited + */ @Input() entity: Entity; - @Input() creatingNew = false; + + /** + * Whether the form should be opened in editing mode or not + */ + @Input() editing = false; + + /** + * The form field definitions. Either as a string or as a FormFieldConfig object. + * Missing information will be fetched from the entity schema definition. + * @param columns The columns which should be displayed + */ @Input() set columns(columns: (FormFieldConfig | string)[][]) { this._columns = columns.map((row) => row.map((field) => { @@ -26,6 +48,9 @@ export class EntityFormComponent implements OnInit { } _columns: FormFieldConfig[][] = []; + /** + * This will be emitted whenever changes have been successfully saved to the entity. + */ @Output() onSave = new EventEmitter(); operationType = OperationType; @@ -35,7 +60,7 @@ export class EntityFormComponent implements OnInit { ngOnInit() { this.buildFormConfig(); - if (this.creatingNew) { + if (this.editing) { this.switchEdit(); } } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 99fad30d42..84be0c6ff5 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -344,7 +344,7 @@ export class EntitySubrecordComponent implements OnChanges { }); dialogRef.componentInstance.columns = columnsCopy; dialogRef.componentInstance.entity = entity; - dialogRef.componentInstance.creatingNew = creatingNew; + dialogRef.componentInstance.editing = creatingNew; dialogRef.componentInstance.onSave.subscribe(() => dialogRef.close()); } From c9ad459d51a6c8d19d09d7bd2423ed074233f529 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 13:54:10 +0200 Subject: [PATCH 199/230] opening details popup in edit mode --- .../entity-subrecord.component.ts | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 84be0c6ff5..77411c4c7d 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -120,10 +120,8 @@ export class EntitySubrecordComponent implements OnChanges { /** * A function which should be executed when a row is clicked or a new entity created. * @param entity The newly created or clicked entity. - * @param creatingNew If a new entity is created, this value is true. */ - @Input() showEntity = (entity: Entity, creatingNew = false) => - this.showEntityInForm(entity, creatingNew); + @Input() showEntity = (entity: Entity) => this.showEntityInForm(entity); /** function returns the background color for each row*/ @Input() getBackgroundColor?: (rec: T) => string = (rec: T) => rec.getColor(); @@ -319,7 +317,7 @@ export class EntitySubrecordComponent implements OnChanges { ); this._entityMapper .save(newRecord) - .then(() => this.showEntity(newRecord, true)); + .then(() => this.showEntity(newRecord)); } /** @@ -332,19 +330,16 @@ export class EntitySubrecordComponent implements OnChanges { } } - private showEntityInForm(entity: Entity, creatingNew = false) { + private showEntityInForm(entity: Entity) { const dialogRef = this.dialog.open(EntityFormComponent, { width: "80%", }); - const columnsCopy = []; - this._columns.forEach((col) => { - const newCol = {}; - Object.assign(newCol, col); - columnsCopy.push([newCol]); - }); - dialogRef.componentInstance.columns = columnsCopy; + // Making a copy of the columns before assigning them + dialogRef.componentInstance.columns = this._columns.map((col) => [ + Object.assign({}, col), + ]); dialogRef.componentInstance.entity = entity; - dialogRef.componentInstance.editing = creatingNew; + dialogRef.componentInstance.editing = true; dialogRef.componentInstance.onSave.subscribe(() => dialogRef.close()); } From 32a92202abd54c122b84082626fa19985d91245e Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 14:59:04 +0200 Subject: [PATCH 200/230] overworked saving process of popups --- .../form/form.component.spec.ts | 2 +- .../entity-details/form/form.component.ts | 25 +++++++++++------- .../entity-form/entity-form.service.ts | 15 +++++------ .../entity-form/entity-form.component.ts | 8 +++++- .../entity-subrecord.component.ts | 26 ++++++++++++------- .../edit-number/edit-number.component.html | 7 ++++- .../edit-percentage.component.html | 7 ++++- 7 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index 102dd0ecd2..b0636faf09 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -43,7 +43,7 @@ describe("FormComponent", () => { const router = fixture.debugElement.injector.get(Router); spyOn(router, "navigate"); component.creatingNew = true; - await component.routeToEntity(testChild); + await component.saveClicked(testChild); expect(router.navigate).toHaveBeenCalledWith(["", testChild.getId()]); }); }); diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index bc2d69986f..5086a6eeb6 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -5,16 +5,17 @@ import { Entity } from "../../../entity/entity"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { getParentUrl } from "../../../../utils/utils"; import { Router } from "@angular/router"; +import { Location } from "@angular/common"; @Component({ selector: "app-form", - template: ` - `, + template: ` `, }) /** * A simple wrapper function of the EntityFormComponent which can be used as a dynamic component @@ -25,7 +26,7 @@ export class FormComponent implements OnInitDynamicComponent { columns: FormFieldConfig[][] = []; creatingNew = false; - constructor(private router: Router) {} + constructor(private router: Router, private location: Location) {} onInitFromDynamicConfig(config: PanelConfig) { this.entity = config.entity; @@ -35,9 +36,15 @@ export class FormComponent implements OnInitDynamicComponent { } } - routeToEntity(entity: Entity) { + saveClicked(entity: Entity) { if (this.creatingNew) { this.router.navigate([getParentUrl(this.router), entity.getId()]); } } + + cancelClicked() { + if (this.creatingNew) { + this.location.back(); + } + } } diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 85deb2db77..a00a304d53 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -56,9 +56,12 @@ export class EntityFormService { const entitySchema = entity.getSchema(); formFields.forEach((formField) => { const propertySchema = entitySchema.get(formField.id); - formConfig[formField.id] = [entity[formField.id]]; - if (formField.required || propertySchema?.required) { - formConfig[formField.id].push(Validators.required); + // Only properties with a schema are editable + if (propertySchema) { + formConfig[formField.id] = [entity[formField.id]]; + if (formField.required || propertySchema?.required) { + formConfig[formField.id].push(Validators.required); + } } }); return this.fb.group(formConfig); @@ -106,11 +109,7 @@ export class EntityFormService { private assignFormValuesToEntity(form: FormGroup, entity: Entity) { Object.keys(form.controls).forEach((key) => { - // Trying to set a getter function will throw an error - const propertyDescriptor = Object.getOwnPropertyDescriptor(entity, key); - if (propertyDescriptor === undefined || propertyDescriptor.writable) { - entity[key] = form.get(key).value; - } + entity[key] = form.get(key).value; }); } } diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index d666a0bbea..111fe73f2f 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -53,6 +53,11 @@ export class EntityFormComponent implements OnInit { */ @Output() onSave = new EventEmitter(); + /** + * This will be emitted whenever the cancel button is pressed. + */ + @Output() onCancel = new EventEmitter(); + operationType = OperationType; form: FormGroup; @@ -78,11 +83,12 @@ export class EntityFormComponent implements OnInit { this.form, this.entity ); - this.switchEdit(); this.onSave.emit(this.entity); + this.switchEdit(); } cancel() { + this.onCancel.emit(); this.buildFormConfig(); } diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 77411c4c7d..6639e1d3a0 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -121,7 +121,7 @@ export class EntitySubrecordComponent implements OnChanges { * A function which should be executed when a row is clicked or a new entity created. * @param entity The newly created or clicked entity. */ - @Input() showEntity = (entity: Entity) => this.showEntityInForm(entity); + @Input() showEntity = (entity: T) => this.showEntityInForm(entity); /** function returns the background color for each row*/ @Input() getBackgroundColor?: (rec: T) => string = (rec: T) => rec.getColor(); @@ -315,9 +315,7 @@ export class EntitySubrecordComponent implements OnChanges { this.recordsDataSource.data = [{ record: newRecord }].concat( this.recordsDataSource.data ); - this._entityMapper - .save(newRecord) - .then(() => this.showEntity(newRecord)); + this._entityMapper.save(newRecord).then(() => this.showEntity(newRecord)); } /** @@ -330,17 +328,25 @@ export class EntitySubrecordComponent implements OnChanges { } } - private showEntityInForm(entity: Entity) { + private showEntityInForm(entity: T) { const dialogRef = this.dialog.open(EntityFormComponent, { width: "80%", }); - // Making a copy of the columns before assigning them - dialogRef.componentInstance.columns = this._columns.map((col) => [ - Object.assign({}, col), - ]); + // Making a copy of the editable columns before assigning them + dialogRef.componentInstance.columns = this._columns + .filter((col) => col.edit) + .map((col) => [Object.assign({}, col)]); dialogRef.componentInstance.entity = entity; dialogRef.componentInstance.editing = true; - dialogRef.componentInstance.onSave.subscribe(() => dialogRef.close()); + dialogRef.componentInstance.onSave.subscribe((updatedEntity: T) => { + dialogRef.close(); + // Trigger the change detection + const rowIndex = this.recordsDataSource.data.findIndex( + (row) => row.record === entity + ); + this.recordsDataSource.data[rowIndex] = { record: updatedEntity }; + }); + dialogRef.componentInstance.onCancel.subscribe(() => dialogRef.close()); } /** diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html index ef8f177907..1b81086035 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html @@ -1,5 +1,10 @@ - + Only numbers are allowed diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html index 04eeaba4da..399b989829 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html @@ -1,5 +1,10 @@ - + Only numbers are allowed From afb024b1fde39e83e1b53e72679dde1b0a0ca5ad Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 16:36:06 +0200 Subject: [PATCH 201/230] fixed some runtime problems --- .../educational-material.component.html | 2 +- .../educational-material.component.ts | 21 +++++++----------- .../entity-form/entity-form.service.ts | 4 ++++ .../entity-form/entity-form.component.ts | 22 +++++++++++++------ .../entity-subrecord.component.ts | 1 + 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.html b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.html index 07b27fb190..da3d3f9b9f 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.html +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.html @@ -5,4 +5,4 @@ > -
Total: {{ getSummary() }}
+
Total: {{ summary }}
diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index 335be5344d..e2e838d509 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -16,6 +16,7 @@ export class EducationalMaterialComponent implements OnChanges, OnInitDynamicComponent { @Input() child: Child; records = new Array(); + summary = ""; columns: FormFieldConfig[] = [ { id: "date", visibleFrom: "xs" }, @@ -50,41 +51,35 @@ export class EducationalMaterialComponent (a, b) => (b.date ? b.date.valueOf() : 0) - (a.date ? a.date.valueOf() : 0) ); + this.updateSummary(); }); } generateNewRecordFactory() { - // define values locally because "this" is a different scope after passing a function as input to another component - const child = this.child.getId(); - return () => { const newAtt = new EducationalMaterial(Date.now().toString()); // use last entered date as default, otherwise today's date newAtt.date = this.records.length > 0 ? this.records[0].date : new Date(); - newAtt.child = child; + newAtt.child = this.child.getId(); return newAtt; }; } - getSummary() { - if (this.records.length === 0) { - return ""; - } - + updateSummary() { const summary = new Map(); this.records.forEach((m) => { - const previousValue = summary.has(m.materialType.id) - ? summary.get(m.materialType.id) + const previousValue = summary.has(m.materialType.label) + ? summary.get(m.materialType.label) : 0; - summary.set(m.materialType.id, previousValue + m.materialAmount); + summary.set(m.materialType.label, previousValue + m.materialAmount); }); let summaryText = ""; summary.forEach( (v, k) => (summaryText = summaryText + k + ": " + v + ", ") ); - return summaryText; + this.summary = summaryText; } } diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index a00a304d53..9143574a87 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -6,6 +6,10 @@ import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; @Injectable() +/** + * This service provides helper functions for creating tables or forms for an entity as well as saving + * new changes correctly to the entity. + */ export class EntityFormService { constructor( private fb: FormBuilder, diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index 111fe73f2f..f706a3860c 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -4,6 +4,7 @@ import { OperationType } from "../../../permissions/entity-permissions.service"; import { FormFieldConfig } from "./FormConfig"; import { FormGroup } from "@angular/forms"; import { EntityFormService } from "../entity-form.service"; +import { AlertService } from "../../../alerts/alert.service"; @Component({ selector: "app-entity-form", @@ -61,7 +62,10 @@ export class EntityFormComponent implements OnInit { operationType = OperationType; form: FormGroup; - constructor(private entityFormService: EntityFormService) {} + constructor( + private entityFormService: EntityFormService, + private alertService: AlertService + ) {} ngOnInit() { this.buildFormConfig(); @@ -79,12 +83,16 @@ export class EntityFormComponent implements OnInit { } async save(): Promise { - this.entity = await this.entityFormService.saveChanges( - this.form, - this.entity - ); - this.onSave.emit(this.entity); - this.switchEdit(); + try { + this.entity = await this.entityFormService.saveChanges( + this.form, + this.entity + ); + this.onSave.emit(this.entity); + this.switchEdit(); + } catch (err) { + this.alertService.addWarning(err.message); + } } cancel() { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 6639e1d3a0..04c2fc9dff 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -345,6 +345,7 @@ export class EntitySubrecordComponent implements OnChanges { (row) => row.record === entity ); this.recordsDataSource.data[rowIndex] = { record: updatedEntity }; + this.recordsDataSource._updateChangeSubscription(); }); dialogRef.componentInstance.onCancel.subscribe(() => dialogRef.close()); } From e846cfa05ddda906dc81fc40ae87b20b4a5fcc24 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 28 Jun 2021 16:47:54 +0200 Subject: [PATCH 202/230] fixed failing tests --- .../entity-form/entity-form.component.spec.ts | 18 +++++++++++------- .../entity-subrecord.component.spec.ts | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts index 26f6c9d711..dcc95d65e8 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts @@ -92,21 +92,25 @@ describe("EntityFormComponent", () => { component.save(); }); - it("reports error when form is invalid", () => { + it("reports error when form is invalid", async () => { const alertService = fixture.debugElement.injector.get(AlertService); - spyOn(alertService, "addDanger"); + spyOn(alertService, "addWarning"); spyOnProperty(component.form, "invalid").and.returnValue(true); - return expectAsync(component.save()).toBeRejected(); + await component.save(); + + expect(alertService.addWarning).toHaveBeenCalled(); }); - it("logs error when saving fails", () => { + it("logs error when saving fails", async () => { const alertService = fixture.debugElement.injector.get(AlertService); - spyOn(alertService, "addDanger"); + spyOn(alertService, "addWarning"); spyOnProperty(component.form, "valid").and.returnValue(true); - mockEntityMapper.save.and.rejectWith("error"); + mockEntityMapper.save.and.rejectWith(); + + await component.save(); - return expectAsync(component.save()).toBeRejected(); + expect(alertService.addWarning).toHaveBeenCalled(); }); it("should add column definitions from property schema", () => { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index 3cf0f8e3ee..06ca21f0a8 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -334,7 +334,7 @@ describe("EntitySubrecordComponent", () => { expect(component.records).toEqual([child]); expect(component.recordsDataSource.data).toContain({ record: child }); - expect(showEntitySpy).toHaveBeenCalledWith(child, true); + expect(showEntitySpy).toHaveBeenCalledWith(child); })); it("should notify when an entity is clicked", (done) => { From 90fff4241b3179f4b02fd86b7298bd326cd98ad3 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 29 Jun 2021 08:44:47 +0200 Subject: [PATCH 203/230] some minor fixes --- .../configurable-enum-datatype.ts | 1 + .../configurable-enum-migration.service.ts | 9 ++++++++- .../entity-form/entity-form/FormConfig.ts | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index ae854f2d79..11c7581451 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -37,6 +37,7 @@ export class ConfigurableEnumDatatype enumId = CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId; } + // The label check is used to also match enums that were automatically created return this.configService .getConfig(enumId) ?.find((option) => option.id === value || option.label === value); diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.ts index 7f5a81630f..e7463eef4d 100644 --- a/src/app/core/configurable-enum/configurable-enum-migration.service.ts +++ b/src/app/core/configurable-enum/configurable-enum-migration.service.ts @@ -3,6 +3,8 @@ import { EntityMapperService } from "../entity/entity-mapper.service"; import { EducationalMaterial } from "../../child-dev-project/educational-material/model/educational-material"; import { Aser } from "../../child-dev-project/aser/model/aser"; import { Entity } from "../entity/entity"; +import { Child } from "../../child-dev-project/children/model/child"; +import { Note } from "../../child-dev-project/notes/model/note"; @Injectable({ providedIn: "root", @@ -11,7 +13,12 @@ export class ConfigurableEnumMigrationService { constructor(private entityMapper: EntityMapperService) {} async migrateSelectionsToConfigurableEnum(): Promise { - const entitiesToMigrate: typeof Entity[] = [Aser, EducationalMaterial]; + const entitiesToMigrate: typeof Entity[] = [ + Aser, + EducationalMaterial, + Child, + Note, + ]; for (const entityConstructor of entitiesToMigrate) { const entities = await this.entityMapper.loadType(entityConstructor); // The entities will automatically be saved correctly once the schema is applied diff --git a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts index 6a5d95a8a5..a8988dfaf4 100644 --- a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts +++ b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts @@ -1,6 +1,6 @@ /** * The general configuration for fields in tables and forms. - * This defines which property is displayed on how it should be displayed. + * This defines which property is displayed and how it should be displayed. * Most information does not need to be provided if a property with schema definitions is displayed. */ export interface FormFieldConfig { From 19adcc7b943ff52b4da906989be8e1e0387c6145 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 10:25:17 +0200 Subject: [PATCH 204/230] undoing warning-level changes --- .../child-dev-project/aser/model/aser.spec.ts | 2 +- src/app/child-dev-project/aser/model/aser.ts | 2 +- .../attendance-calendar.component.ts | 2 +- .../attendance/model/activity-attendance.ts | 2 +- .../attendance/model/attendance-month.spec.ts | 2 +- .../attendance/model/attendance-month.ts | 2 +- .../attendance/model/event-note.spec.ts | 2 +- .../model/recurring-activity.spec.ts | 2 +- .../attendance/model/recurring-activity.ts | 2 +- .../datatype-photo.spec.ts | 2 +- .../child-photo-service/datatype-photo.ts | 2 +- .../children/model/child.spec.ts | 2 +- .../child-dev-project/children/model/child.ts | 2 +- .../model/childSchoolRelation.spec.ts | 2 +- .../children/model/childSchoolRelation.ts | 2 +- .../model/educational-material.spec.ts | 2 +- .../model/educational-material.ts | 2 +- .../health-checkup/model/health-check.spec.ts | 2 +- .../health-checkup/model/health-check.ts | 2 +- .../notes/model/note.spec.ts | 2 +- src/app/child-dev-project/notes/model/note.ts | 2 +- .../note-details/note-details.component.ts | 2 +- .../notes-manager.component.spec.ts | 2 +- .../notes-manager/notes-manager.component.ts | 4 ++-- .../progress-dashboard-config.spec.ts | 2 +- .../progress-dashboard-config.ts | 2 +- .../schools/model/school.spec.ts | 2 +- .../child-dev-project/schools/model/school.ts | 2 +- .../conflict-resolution-list.component.ts | 2 +- .../core/config/config-migration.service.ts | 2 +- src/app/core/config/config.ts | 2 +- .../configurable-enum-datatype.spec.ts | 2 +- .../configurable-enum-migration.service.ts | 2 +- src/app/core/database/query-data-source.ts | 2 +- src/app/core/demo-data/demo-data-generator.ts | 2 +- .../entity-details/EntityDetailsConfig.ts | 2 +- .../entity-details.component.ts | 2 +- .../entity-details/form/form.component.ts | 2 +- .../entity-form/entity-form.service.spec.ts | 2 +- .../entity-form/entity-form.service.ts | 2 +- .../entity-form/entity-form.component.spec.ts | 2 +- .../entity-form/entity-form.component.ts | 2 +- .../entity-list/EntityListConfig.ts | 2 +- .../entity-list/entity-list.component.spec.ts | 2 +- .../entity-list/entity-list.component.ts | 2 +- .../entity-list/filter-generator.service.ts | 2 +- .../list-filter/list-filter.component.ts | 2 +- .../entity-subrecord.component.spec.ts | 2 +- .../entity-subrecord.component.ts | 2 +- .../list-paginator.component.ts | 2 +- .../edit-entity-array.component.ts | 2 +- .../edit-single-entity.component.ts | 2 +- .../entity-select.component.spec.ts | 2 +- .../entity-select/entity-select.component.ts | 2 +- .../display-entity-array.component.ts | 2 +- .../display-entity.component.ts | 2 +- .../readonly-function/entity-function.pipe.ts | 2 +- .../readonly-function.component.ts | 2 +- .../view-components/view-component.ts | 2 +- .../entity/database-field.decorator.spec.ts | 2 +- .../database-indexing.service.ts | 2 +- .../core/entity/entity-config.service.spec.ts | 2 +- src/app/core/entity/entity-config.service.ts | 2 +- .../core/entity/entity-mapper.service.spec.ts | 2 +- src/app/core/entity/entity-mapper.service.ts | 4 ++-- .../core/entity/mock-entity-mapper-service.ts | 4 ++-- .../entity/{ => model}/entity-update.spec.ts | 0 .../core/entity/{ => model}/entity-update.ts | 0 .../core/entity/{ => model}/entity.spec.ts | 4 ++-- src/app/core/entity/{ => model}/entity.ts | 15 +++++++-------- src/app/core/entity/model/warning-level.ts | 19 +++++++++++++++++++ .../schema-datatypes/datatype-map.spec.ts | 2 +- .../datatype-schema-embed.spec.ts | 2 +- .../schema-datatypes/datatype-schema-embed.ts | 2 +- .../entity/schema/entity-schema-datatype.ts | 2 +- .../schema/entity-schema.service.spec.ts | 2 +- .../entity/schema/entity-schema.service.ts | 2 +- .../form-dialog-wrapper.component.ts | 2 +- .../form-dialog/form-dialog.service.spec.ts | 2 +- .../core/form-dialog/form-dialog.service.ts | 2 +- .../form-dialog/shows-entity.interface.ts | 2 +- ...disable-entity-operation.directive.spec.ts | 2 +- .../disable-entity-operation.directive.ts | 2 +- .../entity-permissions.service.spec.ts | 2 +- .../permissions/entity-permissions.service.ts | 2 +- src/app/core/ui/search/search.component.ts | 2 +- src/app/core/user/user.spec.ts | 2 +- src/app/core/user/user.ts | 2 +- .../demo-historical-data-generator.ts | 2 +- .../historical-data.service.spec.ts | 2 +- .../historical-data.component.spec.ts | 2 +- .../historical-data.component.ts | 2 +- .../historical-data/historical-entity-data.ts | 2 +- src/app/features/reporting/query.service.ts | 2 +- src/app/utils/expect-entity-data.spec.ts | 2 +- 95 files changed, 121 insertions(+), 103 deletions(-) rename src/app/core/entity/{ => model}/entity-update.spec.ts (100%) rename src/app/core/entity/{ => model}/entity-update.ts (100%) rename src/app/core/entity/{ => model}/entity.spec.ts (96%) rename src/app/core/entity/{ => model}/entity.ts (93%) create mode 100644 src/app/core/entity/model/warning-level.ts diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index cc19e06c9b..7237201afe 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -18,7 +18,7 @@ import { Aser } from "./aser"; import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { mathLevels } from "./mathLevels"; import { readingLevels } from "./readingLevels"; diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index fe5c0b9cdc..b836aa3c1e 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { warningLevels } from "../../warning-level"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; diff --git a/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts b/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts index f56801e28f..8d8b739fdc 100644 --- a/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts +++ b/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts @@ -19,7 +19,7 @@ import { } from "../model/calculate-average-event-attendance"; import { EventNote } from "../model/event-note"; import { RecurringActivity } from "../model/recurring-activity"; -import { applyUpdate } from "../../../core/entity/entity-update"; +import { applyUpdate } from "../../../core/entity/model/entity-update"; import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { AttendanceService } from "../attendance.service"; diff --git a/src/app/child-dev-project/attendance/model/activity-attendance.ts b/src/app/child-dev-project/attendance/model/activity-attendance.ts index bfeeaf9709..906126cead 100644 --- a/src/app/child-dev-project/attendance/model/activity-attendance.ts +++ b/src/app/child-dev-project/attendance/model/activity-attendance.ts @@ -2,7 +2,7 @@ import { AttendanceLogicalStatus, AttendanceStatusType, } from "./attendance-status"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { RecurringActivity } from "./recurring-activity"; import { defaultAttendanceStatusTypes } from "../../../core/config/default-config/default-attendance-status-types"; import { warningLevels } from "../../warning-level"; diff --git a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts index 3e61ced23d..bfa28ef314 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts @@ -18,7 +18,7 @@ import { AttendanceMonth, daysInMonth } from "./attendance-month"; import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; describe("AttendanceMonth", () => { diff --git a/src/app/child-dev-project/attendance/model/attendance-month.ts b/src/app/child-dev-project/attendance/model/attendance-month.ts index b326ca8551..f17b0dc1ef 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { warningLevels } from "../../warning-level"; import { AttendanceDay } from "./attendance-day"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; diff --git a/src/app/child-dev-project/attendance/model/event-note.spec.ts b/src/app/child-dev-project/attendance/model/event-note.spec.ts index 6f7e608a76..24e884216c 100644 --- a/src/app/child-dev-project/attendance/model/event-note.spec.ts +++ b/src/app/child-dev-project/attendance/model/event-note.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EventNote } from "./event-note"; describe("EventNote", () => { diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts b/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts index 6707192b3a..06bb0cbdea 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts @@ -18,7 +18,7 @@ import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { RecurringActivity } from "./recurring-activity"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { InteractionType } from "../../notes/model/interaction-type.interface"; import { ConfigurableEnumDatatype } from "../../../core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype"; diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.ts b/src/app/child-dev-project/attendance/model/recurring-activity.ts index 68d5e2aaaa..9006804e80 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { Note } from "../../notes/model/note"; diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 2fe1b6de5a..a94bcd423a 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -19,7 +19,7 @@ import { TestBed } from "@angular/core/testing"; import { SafeUrl } from "@angular/platform-browser"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ChildPhotoService } from "./child-photo.service"; import { BehaviorSubject } from "rxjs"; import { PhotoDatatype } from "./datatype-photo"; diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index 85112757c7..07ada75626 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -19,7 +19,7 @@ import { EntitySchemaDatatype } from "../../../core/entity/schema/entity-schema- import { ChildPhotoService } from "./child-photo.service"; import { EntitySchemaField } from "../../../core/entity/schema/entity-schema-field"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { Photo } from "./photo"; import { SafeUrl } from "@angular/platform-browser"; import { BehaviorSubject } from "rxjs"; diff --git a/src/app/child-dev-project/children/model/child.spec.ts b/src/app/child-dev-project/children/model/child.spec.ts index 5dc7ed46e5..fa4406b894 100644 --- a/src/app/child-dev-project/children/model/child.spec.ts +++ b/src/app/child-dev-project/children/model/child.spec.ts @@ -17,7 +17,7 @@ import { Child } from "./child"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { PhotoDatatype } from "../child-photo-service/datatype-photo"; import { genders } from "./genders"; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index fafb58846e..e5e1ef3124 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +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/configurable-enum/configurable-enum.interface"; diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts index 5ccae6cbeb..3ae8fe484d 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts @@ -17,7 +17,7 @@ import { waitForAsync } from "@angular/core/testing"; import { ChildSchoolRelation } from "./childSchoolRelation"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import moment from "moment"; diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.ts b/src/app/child-dev-project/children/model/childSchoolRelation.ts index 1dbb29b905..cc18b48539 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import moment from "moment"; diff --git a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts index 838a13f26e..00a08a98eb 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts @@ -17,7 +17,7 @@ import { waitForAsync } from "@angular/core/testing"; import { EducationalMaterial } from "./educational-material"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { materials } from "./materials"; diff --git a/src/app/child-dev-project/educational-material/model/educational-material.ts b/src/app/child-dev-project/educational-material/model/educational-material.ts index 99a1d4f370..c22274bcd8 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +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/configurable-enum/configurable-enum.interface"; diff --git a/src/app/child-dev-project/health-checkup/model/health-check.spec.ts b/src/app/child-dev-project/health-checkup/model/health-check.spec.ts index 1b165fbaad..c9d4ed5d09 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.spec.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.spec.ts @@ -16,7 +16,7 @@ */ import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HealthCheck } from "./health-check"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; diff --git a/src/app/child-dev-project/health-checkup/model/health-check.ts b/src/app/child-dev-project/health-checkup/model/health-check.ts index e87838a85c..8eca16bf91 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { warningLevels } from "../../warning-level"; diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index cc908701ad..25fdc10595 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -2,7 +2,7 @@ import { Note } from "./note"; import { warningLevels } from "../../warning-level"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ATTENDANCE_STATUS_CONFIG_ID, AttendanceLogicalStatus, diff --git a/src/app/child-dev-project/notes/model/note.ts b/src/app/child-dev-project/notes/model/note.ts index 327b8711e5..eb6cfb0be5 100644 --- a/src/app/child-dev-project/notes/model/note.ts +++ b/src/app/child-dev-project/notes/model/note.ts @@ -16,7 +16,7 @@ */ import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { warningLevels } from "../../warning-level"; import { diff --git a/src/app/child-dev-project/notes/note-details/note-details.component.ts b/src/app/child-dev-project/notes/note-details/note-details.component.ts index 91ea1c4016..e0fbb66b0d 100644 --- a/src/app/child-dev-project/notes/note-details/note-details.component.ts +++ b/src/app/child-dev-project/notes/note-details/note-details.component.ts @@ -2,7 +2,7 @@ import { Component, Input, Optional, ViewChild } from "@angular/core"; import { Note } from "../model/note"; import { ShowsEntity } from "../../../core/form-dialog/shows-entity.interface"; import { MatDialogRef } from "@angular/material/dialog"; -import { Entity, EntityConstructor } from "../../../core/entity/entity"; +import { Entity, EntityConstructor } from "../../../core/entity/model/entity"; import { INTERACTION_TYPE_CONFIG_ID } from "../model/interaction-type.interface"; import { Child } from "../../children/model/child"; import { User } from "../../../core/user/user"; diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.spec.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.spec.ts index 8b75180094..03e96bde26 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.spec.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.spec.ts @@ -31,7 +31,7 @@ import { EntityListComponent } from "../../../core/entity-components/entity-list import { EventNote } from "app/child-dev-project/attendance/model/event-note"; import { BehaviorSubject } from "rxjs"; import { BackupService } from "../../../core/admin/services/backup.service"; -import { UpdatedEntity } from "../../../core/entity/entity-update"; +import { UpdatedEntity } from "../../../core/entity/model/entity-update"; describe("NotesManagerComponent", () => { let component: NotesManagerComponent; diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts index cd774aa416..4c2fd75632 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts @@ -11,11 +11,11 @@ import { FormDialogService } from "../../../core/form-dialog/form-dialog.service import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { LoggingService } from "../../../core/logging/logging.service"; import { EntityListComponent } from "../../../core/entity-components/entity-list/entity-list.component"; -import { applyUpdate } from "../../../core/entity/entity-update"; +import { applyUpdate } from "../../../core/entity/model/entity-update"; import { EntityListConfig } from "../../../core/entity-components/entity-list/EntityListConfig"; import { Input } from "@angular/core"; import { EventNote } from "../../attendance/model/event-note"; -import { EntityConstructor } from "../../../core/entity/entity"; +import { EntityConstructor } from "../../../core/entity/model/entity"; /** * additional config specifically for NotesManagerComponent diff --git a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts index bd6d541bd1..c3c178c179 100644 --- a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts +++ b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts @@ -16,7 +16,7 @@ */ import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ProgressDashboardConfig } from "./progress-dashboard-config"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; diff --git a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts index 66b7fa8189..56de0330ee 100644 --- a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts +++ b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; diff --git a/src/app/child-dev-project/schools/model/school.spec.ts b/src/app/child-dev-project/schools/model/school.spec.ts index 461498fafe..f8c8ee235d 100644 --- a/src/app/child-dev-project/schools/model/school.spec.ts +++ b/src/app/child-dev-project/schools/model/school.spec.ts @@ -17,7 +17,7 @@ import { waitForAsync } from "@angular/core/testing"; import { School } from "./school"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; describe("School Entity", () => { diff --git a/src/app/child-dev-project/schools/model/school.ts b/src/app/child-dev-project/schools/model/school.ts index 29ed05745f..a96cd8244e 100644 --- a/src/app/child-dev-project/schools/model/school.ts +++ b/src/app/child-dev-project/schools/model/school.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; diff --git a/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts b/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts index cdc17397a5..25321199b8 100644 --- a/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts +++ b/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, Component, Optional, ViewChild } from "@angular/core"; import { MatPaginator } from "@angular/material/paginator"; import { QueryDataSource } from "../../core/database/query-data-source"; -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { Database } from "../../core/database/database"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index a808bbf05f..09bf234cc6 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -10,7 +10,7 @@ import { } from "../entity-components/entity-list/EntityListConfig"; import { FormFieldConfig } from "../entity-components/entity-form/entity-form/FormConfig"; import { ENTITY_MAP } from "../entity-components/entity-details/entity-details.component"; -import { Entity, EntityConstructor } from "../entity/entity"; +import { Entity, EntityConstructor } from "../entity/model/entity"; import { EntityConfig, EntityConfigService, diff --git a/src/app/core/config/config.ts b/src/app/core/config/config.ts index 3a56dad7dd..8853c0ba8b 100644 --- a/src/app/core/config/config.ts +++ b/src/app/core/config/config.ts @@ -1,4 +1,4 @@ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DatabaseField } from "../entity/database-field.decorator"; import { DatabaseEntity } from "../entity/database-entity.decorator"; diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts index b579350b56..cfe25050e5 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts @@ -18,7 +18,7 @@ import { ConfigurableEnumConfig, ConfigurableEnumValue, } from "../configurable-enum.interface"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { DatabaseField } from "../../entity/database-field.decorator"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { TestBed, waitForAsync } from "@angular/core/testing"; diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.ts index e7463eef4d..552b649d3a 100644 --- a/src/app/core/configurable-enum/configurable-enum-migration.service.ts +++ b/src/app/core/configurable-enum/configurable-enum-migration.service.ts @@ -2,7 +2,7 @@ import { Injectable } from "@angular/core"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { EducationalMaterial } from "../../child-dev-project/educational-material/model/educational-material"; import { Aser } from "../../child-dev-project/aser/model/aser"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { Child } from "../../child-dev-project/children/model/child"; import { Note } from "../../child-dev-project/notes/model/note"; diff --git a/src/app/core/database/query-data-source.ts b/src/app/core/database/query-data-source.ts index 9837e4259b..7c7d33e4f0 100644 --- a/src/app/core/database/query-data-source.ts +++ b/src/app/core/database/query-data-source.ts @@ -1,7 +1,7 @@ import { CollectionViewer, DataSource } from "@angular/cdk/collections"; import { BehaviorSubject, Observable } from "rxjs"; import { MatPaginator } from "@angular/material/paginator"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { Database } from "./database"; /** diff --git a/src/app/core/demo-data/demo-data-generator.ts b/src/app/core/demo-data/demo-data-generator.ts index 4d7393b36a..7967f88815 100644 --- a/src/app/core/demo-data/demo-data-generator.ts +++ b/src/app/core/demo-data/demo-data-generator.ts @@ -1,4 +1,4 @@ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Abstract base class for demo data generator services. diff --git a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts index f5120240f4..11995e0d3f 100644 --- a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts +++ b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; /** * The configuration for a entity details page diff --git a/src/app/core/entity-components/entity-details/entity-details.component.ts b/src/app/core/entity-components/entity-details/entity-details.component.ts index 4b5f4217df..480626e8b1 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.ts @@ -8,7 +8,7 @@ import { Panel, PanelComponent, } from "./EntityDetailsConfig"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { School } from "../../../child-dev-project/schools/model/school"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { getUrlWithoutParams } from "../../../utils/utils"; diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 5086a6eeb6..a7c5743771 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -1,7 +1,7 @@ import { Component } from "@angular/core"; import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../EntityDetailsConfig"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { getParentUrl } from "../../../../utils/utils"; import { Router } from "@angular/router"; diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index 258a45663c..c2edb79bba 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -5,7 +5,7 @@ import { FormBuilder } from "@angular/forms"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { EntityFormModule } from "./entity-form.module"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; describe("EntityFormService", () => { let service: EntityFormService; diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 9143574a87..882bd99044 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -1,7 +1,7 @@ import { Injectable } from "@angular/core"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { FormFieldConfig } from "./entity-form/FormConfig"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts index dcc95d65e8..9812f1e362 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { EntityFormComponent } from "./entity-form.component"; import { ChildPhotoService } from "../../../../child-dev-project/children/child-photo-service/child-photo.service"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { User } from "../../../user/user"; import { RouterTestingModule } from "@angular/router/testing"; diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index f706a3860c..1b8bd940ff 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { OperationType } from "../../../permissions/entity-permissions.service"; import { FormFieldConfig } from "./FormConfig"; import { FormGroup } from "@angular/forms"; diff --git a/src/app/core/entity-components/entity-list/EntityListConfig.ts b/src/app/core/entity-components/entity-list/EntityListConfig.ts index 147686eeff..fdf1f5207d 100644 --- a/src/app/core/entity-components/entity-list/EntityListConfig.ts +++ b/src/app/core/entity-components/entity-list/EntityListConfig.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { FilterSelectionOption } from "../../filter/filter-selection/filter-selection"; import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 1d4255da32..e8f039f9ac 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -5,7 +5,7 @@ import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { RouterTestingModule } from "@angular/router/testing"; import { SimpleChange } from "@angular/core"; import { BooleanFilterConfig, EntityListConfig } from "./EntityListConfig"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { User } from "../../user/user"; import { SessionService } from "../../session/session-service/session.service"; diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 31b9896db7..14453497a8 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -16,7 +16,7 @@ import { FilterConfig, GroupConfig, } from "./EntityListConfig"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { OperationType } from "../../permissions/entity-permissions.service"; import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index 5a3099c100..ffc733bb31 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -9,7 +9,7 @@ import { PrebuiltFilterConfig, } from "./EntityListConfig"; import { ENTITY_MAP } from "../entity-details/entity-details.component"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { CONFIGURABLE_ENUM_CONFIG_PREFIX, ConfigurableEnumConfig, diff --git a/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts b/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts index 276f554a8b..3282e0297e 100644 --- a/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts +++ b/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { FilterSelection } from "../../../filter/filter-selection/filter-selection"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; @Component({ selector: "app-list-filter", diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts index d5f31a0d0a..13984588c1 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.spec.ts @@ -13,7 +13,7 @@ import { } from "./entity-subrecord.component"; import { RouterTestingModule } from "@angular/router/testing"; import { EntitySubrecordModule } from "../entity-subrecord.module"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { SimpleChange } from "@angular/core"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { MatNativeDateModule } from "@angular/material/core"; diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 6339fc75fc..793803c70d 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -11,7 +11,7 @@ import { MatTableDataSource } from "@angular/material/table"; import { MediaChange, MediaObserver } from "@angular/flex-layout"; import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { AlertService } from "../../../alerts/alert.service"; import { Subscription } from "rxjs"; diff --git a/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts index 9e4698b636..abcb5db41f 100644 --- a/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts +++ b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts @@ -6,7 +6,7 @@ import { SimpleChanges, AfterViewInit, } from "@angular/core"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { MatPaginator, PageEvent } from "@angular/material/paginator"; import { MatTableDataSource } from "@angular/material/table"; import { User } from "../../../user/user"; diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts index 251bcc6d99..ef88542e17 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts @@ -1,6 +1,6 @@ import { Component } from "@angular/core"; import { EditComponent, EditPropertyConfig } from "../edit-component"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Component({ selector: "app-edit-entity-array", diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts index 1915a3c13a..336a83e316 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { EditComponent, EditPropertyConfig } from "../edit-component"; import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Component({ selector: "app-edit-single-entity", diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts index 61c2a2102d..15abdaa88e 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts @@ -10,7 +10,7 @@ import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatFormFieldModule } from "@angular/material/form-field"; import { MatChipsModule } from "@angular/material/chips"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { ReactiveFormsModule } from "@angular/forms"; import { mockEntityMapper } from "../../../entity/mock-entity-mapper-service"; import { User } from "../../../user/user"; diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts index 451f017ce5..3e3524f463 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts @@ -9,7 +9,7 @@ import { SimpleChanges, } from "@angular/core"; import { ENTER, COMMA } from "@angular/cdk/keycodes"; -import { Entity, EntityConstructor } from "../../../entity/entity"; +import { Entity, EntityConstructor } from "../../../entity/model/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { BehaviorSubject, Observable } from "rxjs"; import { FormControl } from "@angular/forms"; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts index 8fc8bc48b2..706fd772e7 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { ViewComponent } from "../view-component"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 43763f00fa..c393bac85e 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from "@angular/core"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts index 276e22dd8d..5ac8760a46 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from "@angular/core"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Pipe({ name: "entityFunction", diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts index fe2d8ca61d..f86769e355 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts @@ -1,7 +1,7 @@ import { Component } from "@angular/core"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { ViewComponent } from "../view-component"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Component({ selector: "app-readonly-function", diff --git a/src/app/core/entity-components/entity-utils/view-components/view-component.ts b/src/app/core/entity-components/entity-utils/view-components/view-component.ts index b6c73f4253..4011a22759 100644 --- a/src/app/core/entity-components/entity-utils/view-components/view-component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/view-component.ts @@ -1,6 +1,6 @@ import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; import { ViewPropertyConfig } from "../../entity-list/EntityListConfig"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; export abstract class ViewComponent implements OnInitDynamicComponent { entity: Entity; diff --git a/src/app/core/entity/database-field.decorator.spec.ts b/src/app/core/entity/database-field.decorator.spec.ts index ef979efe61..6a11fb77f1 100644 --- a/src/app/core/entity/database-field.decorator.spec.ts +++ b/src/app/core/entity/database-field.decorator.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { DatabaseField } from "./database-field.decorator"; class TestClass extends Entity { diff --git a/src/app/core/entity/database-indexing/database-indexing.service.ts b/src/app/core/entity/database-indexing/database-indexing.service.ts index 6404b865ce..9b85201204 100644 --- a/src/app/core/entity/database-indexing/database-indexing.service.ts +++ b/src/app/core/entity/database-indexing/database-indexing.service.ts @@ -19,7 +19,7 @@ import { Injectable } from "@angular/core"; import { Database, QueryOptions } from "../../database/database"; import { BehaviorSubject, Observable } from "rxjs"; import { BackgroundProcessState } from "../../sync-status/background-process-state.interface"; -import { Entity, EntityConstructor } from "../entity"; +import { Entity, EntityConstructor } from "../model/entity"; import { EntitySchemaService } from "../schema/entity-schema.service"; import { first } from "rxjs/operators"; diff --git a/src/app/core/entity/entity-config.service.spec.ts b/src/app/core/entity/entity-config.service.spec.ts index 56f341baed..a2012c1e1e 100644 --- a/src/app/core/entity/entity-config.service.spec.ts +++ b/src/app/core/entity/entity-config.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed } from "@angular/core/testing"; import { EntityConfig, EntityConfigService } from "./entity-config.service"; import { DatabaseEntity } from "./database-entity.decorator"; import { DatabaseField } from "./database-field.decorator"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { ConfigService } from "../config/config.service"; describe("EntityConfigService", () => { diff --git a/src/app/core/entity/entity-config.service.ts b/src/app/core/entity/entity-config.service.ts index 8b0f44a6e3..1c44fd0863 100644 --- a/src/app/core/entity/entity-config.service.ts +++ b/src/app/core/entity/entity-config.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { ConfigService } from "../config/config.service"; import { EntitySchemaField } from "./schema/entity-schema-field"; import { addPropertySchema } from "./database-field.decorator"; diff --git a/src/app/core/entity/entity-mapper.service.spec.ts b/src/app/core/entity/entity-mapper.service.spec.ts index 160ce39b51..e33f9573fb 100644 --- a/src/app/core/entity/entity-mapper.service.spec.ts +++ b/src/app/core/entity/entity-mapper.service.spec.ts @@ -16,7 +16,7 @@ */ import { EntityMapperService } from "./entity-mapper.service"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { EntitySchemaService } from "./schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { PouchDatabase } from "../database/pouch-database"; diff --git a/src/app/core/entity/entity-mapper.service.ts b/src/app/core/entity/entity-mapper.service.ts index 428044e3ba..c9cc4248da 100644 --- a/src/app/core/entity/entity-mapper.service.ts +++ b/src/app/core/entity/entity-mapper.service.ts @@ -17,10 +17,10 @@ import { Injectable } from "@angular/core"; import { Database } from "../database/database"; -import { Entity, EntityConstructor } from "./entity"; +import { Entity, EntityConstructor } from "./model/entity"; import { EntitySchemaService } from "./schema/entity-schema.service"; import { Observable, Subject } from "rxjs"; -import { UpdatedEntity } from "./entity-update"; +import { UpdatedEntity } from "./model/entity-update"; /** * Handles loading and saving of data for any higher-level feature module. diff --git a/src/app/core/entity/mock-entity-mapper-service.ts b/src/app/core/entity/mock-entity-mapper-service.ts index 6200fbecaa..a39ff937fd 100644 --- a/src/app/core/entity/mock-entity-mapper-service.ts +++ b/src/app/core/entity/mock-entity-mapper-service.ts @@ -1,6 +1,6 @@ -import { Entity, EntityConstructor } from "./entity"; +import { Entity, EntityConstructor } from "./model/entity"; import { EntityMapperService } from "./entity-mapper.service"; -import { UpdatedEntity } from "./entity-update"; +import { UpdatedEntity } from "./model/entity-update"; import { NEVER, Observable } from "rxjs"; export function mockEntityMapper( diff --git a/src/app/core/entity/entity-update.spec.ts b/src/app/core/entity/model/entity-update.spec.ts similarity index 100% rename from src/app/core/entity/entity-update.spec.ts rename to src/app/core/entity/model/entity-update.spec.ts diff --git a/src/app/core/entity/entity-update.ts b/src/app/core/entity/model/entity-update.ts similarity index 100% rename from src/app/core/entity/entity-update.ts rename to src/app/core/entity/model/entity-update.ts diff --git a/src/app/core/entity/entity.spec.ts b/src/app/core/entity/model/entity.spec.ts similarity index 96% rename from src/app/core/entity/entity.spec.ts rename to src/app/core/entity/model/entity.spec.ts index 2eb1bbaa8d..afd1bf6c67 100644 --- a/src/app/core/entity/entity.spec.ts +++ b/src/app/core/entity/model/entity.spec.ts @@ -17,8 +17,8 @@ import { Entity } from "./entity"; import { waitForAsync } from "@angular/core/testing"; -import { EntitySchemaService } from "./schema/entity-schema.service"; -import { DatabaseField } from "./database-field.decorator"; +import { EntitySchemaService } from "../schema/entity-schema.service"; +import { DatabaseField } from "../database-field.decorator"; describe("Entity", () => { let entitySchemaService: EntitySchemaService; diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/model/entity.ts similarity index 93% rename from src/app/core/entity/entity.ts rename to src/app/core/entity/model/entity.ts index c51026e0e6..4a951ea1e7 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/model/entity.ts @@ -16,10 +16,9 @@ */ import { v4 as uuid } from "uuid"; -import { EntitySchema } from "./schema/entity-schema"; -import { DatabaseField } from "./database-field.decorator"; -import { warningLevels } from "../../child-dev-project/warning-level"; -import { ConfigurableEnumValue } from "../configurable-enum/configurable-enum.interface"; +import { EntitySchema } from "../schema/entity-schema"; +import { DatabaseField } from "../database-field.decorator"; +import { getWarningLevelColor, WarningLevel } from "./warning-level"; /** * This represents a static class of type . @@ -203,16 +202,16 @@ export class Entity { * Used by some generic UI components to set the color for the entity instance. * Override this method as needed. */ - public getColor() { - return this.getWarningLevel().color; + public getColor(): string { + return getWarningLevelColor(this.getWarningLevel()); } /** * Override getWarningLevel() to define when the entity is in a critical condition and should be color-coded * and highlighted in generic components of the UI. */ - public getWarningLevel(): ConfigurableEnumValue { - return warningLevels.find((warning) => warning.id === ""); + public getWarningLevel(): WarningLevel { + return WarningLevel.OK; } /** diff --git a/src/app/core/entity/model/warning-level.ts b/src/app/core/entity/model/warning-level.ts new file mode 100644 index 0000000000..f93225f730 --- /dev/null +++ b/src/app/core/entity/model/warning-level.ts @@ -0,0 +1,19 @@ +export enum WarningLevel { + WARNING = "WARNING", + URGENT = "URGENT", + OK = "OK", + NONE = "", +} + +export function getWarningLevelColor(warningLevel: WarningLevel) { + switch (warningLevel) { + case WarningLevel.WARNING: + return "#ffa50080"; + case WarningLevel.URGENT: + return "#fd727280"; + case WarningLevel.OK: + return "#90ee9040"; + default: + return "#ffa50080"; + } +} diff --git a/src/app/core/entity/schema-datatypes/datatype-map.spec.ts b/src/app/core/entity/schema-datatypes/datatype-map.spec.ts index 55ddad4702..00b4cd4e58 100644 --- a/src/app/core/entity/schema-datatypes/datatype-map.spec.ts +++ b/src/app/core/entity/schema-datatypes/datatype-map.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { waitForAsync } from "@angular/core/testing"; import { DatabaseField } from "../database-field.decorator"; import { EntitySchemaService } from "../schema/entity-schema.service"; diff --git a/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts b/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts index 0ba7d41612..499aa39df1 100644 --- a/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts +++ b/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { DatabaseField } from "../database-field.decorator"; import { EntitySchemaService } from "../schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; diff --git a/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts b/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts index ca5c9d0519..b00682c4d3 100644 --- a/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts +++ b/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts @@ -18,7 +18,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; import { EntitySchemaField } from "../schema/entity-schema-field"; import { EntitySchemaService } from "../schema/entity-schema.service"; -import { EntityConstructor } from "../entity"; +import { EntityConstructor } from "../model/entity"; /** * Datatype for the EntitySchemaService transforming values of complex objects recursively. diff --git a/src/app/core/entity/schema/entity-schema-datatype.ts b/src/app/core/entity/schema/entity-schema-datatype.ts index a7a2e0cdfb..bd00573115 100644 --- a/src/app/core/entity/schema/entity-schema-datatype.ts +++ b/src/app/core/entity/schema/entity-schema-datatype.ts @@ -17,7 +17,7 @@ import { EntitySchemaField } from "./entity-schema-field"; import { EntitySchemaService } from "./entity-schema.service"; -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; /** * Interface to be implemented by any Datatype transformer of the Schema system. diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 09c14a2f52..d994b21aa7 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { waitForAsync } from "@angular/core/testing"; import { EntitySchemaService } from "./entity-schema.service"; import { DatabaseField } from "../database-field.decorator"; diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index 4e59645456..17db13b74f 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { EntitySchemaDatatype } from "./entity-schema-datatype"; import { Injectable } from "@angular/core"; import { defaultEntitySchemaDatatype } from "../schema-datatypes/datatype-default"; diff --git a/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts b/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts index c784494ffb..8494f93c7d 100644 --- a/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts +++ b/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts @@ -7,7 +7,7 @@ import { Output, } from "@angular/core"; import { EntityMapperService } from "../../entity/entity-mapper.service"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { MatDialogRef } from "@angular/material/dialog"; /** diff --git a/src/app/core/form-dialog/form-dialog.service.spec.ts b/src/app/core/form-dialog/form-dialog.service.spec.ts index 0fb836a852..cb545e8296 100644 --- a/src/app/core/form-dialog/form-dialog.service.spec.ts +++ b/src/app/core/form-dialog/form-dialog.service.spec.ts @@ -3,7 +3,7 @@ import { MatDialogModule } from "@angular/material/dialog"; import { FormDialogService } from "./form-dialog.service"; import { Component, EventEmitter, Input } from "@angular/core"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { ShowsEntity } from "./shows-entity.interface"; import { FormDialogModule } from "./form-dialog.module"; import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; diff --git a/src/app/core/form-dialog/form-dialog.service.ts b/src/app/core/form-dialog/form-dialog.service.ts index d7769c7abf..fba888075c 100644 --- a/src/app/core/form-dialog/form-dialog.service.ts +++ b/src/app/core/form-dialog/form-dialog.service.ts @@ -5,7 +5,7 @@ import { ConfirmationDialogService } from "../confirmation-dialog/confirmation-d import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; import { ShowsEntity } from "./shows-entity.interface"; import { OnInitDynamicComponent } from "../view/dynamic-components/on-init-dynamic-component.interface"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Inject this service instead of MatDialog to display a form or details view as a modal diff --git a/src/app/core/form-dialog/shows-entity.interface.ts b/src/app/core/form-dialog/shows-entity.interface.ts index 18f5a393c8..6952c05522 100644 --- a/src/app/core/form-dialog/shows-entity.interface.ts +++ b/src/app/core/form-dialog/shows-entity.interface.ts @@ -1,5 +1,5 @@ import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Interface to be implemented by Components so that they can be used with {@link FormDialogService}. diff --git a/src/app/core/permissions/disable-entity-operation.directive.spec.ts b/src/app/core/permissions/disable-entity-operation.directive.spec.ts index c65cc9be3c..6aa6a89941 100644 --- a/src/app/core/permissions/disable-entity-operation.directive.spec.ts +++ b/src/app/core/permissions/disable-entity-operation.directive.spec.ts @@ -5,7 +5,7 @@ import { } from "./entity-permissions.service"; import { Component, ElementRef, ViewChild } from "@angular/core"; import { fakeAsync, TestBed, tick } from "@angular/core/testing"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { MatTooltipModule } from "@angular/material/tooltip"; describe("DisableEntityOperationDirective", () => { diff --git a/src/app/core/permissions/disable-entity-operation.directive.ts b/src/app/core/permissions/disable-entity-operation.directive.ts index a8c3527b62..bee1764ce5 100644 --- a/src/app/core/permissions/disable-entity-operation.directive.ts +++ b/src/app/core/permissions/disable-entity-operation.directive.ts @@ -11,7 +11,7 @@ import { EntityPermissionsService, OperationType, } from "./entity-permissions.service"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DisabledWrapperComponent } from "./disabled-wrapper/disabled-wrapper.component"; /** diff --git a/src/app/core/permissions/entity-permissions.service.spec.ts b/src/app/core/permissions/entity-permissions.service.spec.ts index 944436e410..6c7eebbfe7 100644 --- a/src/app/core/permissions/entity-permissions.service.spec.ts +++ b/src/app/core/permissions/entity-permissions.service.spec.ts @@ -6,7 +6,7 @@ import { } from "./entity-permissions.service"; import { SessionService } from "../session/session-service/session.service"; import { User } from "../user/user"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { EntityConfigService } from "../entity/entity-config.service"; describe("EntityPermissionsService", () => { diff --git a/src/app/core/permissions/entity-permissions.service.ts b/src/app/core/permissions/entity-permissions.service.ts index 1053a56f8f..f13e914a0b 100644 --- a/src/app/core/permissions/entity-permissions.service.ts +++ b/src/app/core/permissions/entity-permissions.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { SessionService } from "../session/session-service/session.service"; import { EntityConfigService } from "../entity/entity-config.service"; diff --git a/src/app/core/ui/search/search.component.ts b/src/app/core/ui/search/search.component.ts index d1756d6709..f1fc3d7bd3 100644 --- a/src/app/core/ui/search/search.component.ts +++ b/src/app/core/ui/search/search.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { Child } from "../../../child-dev-project/children/model/child"; import { School } from "../../../child-dev-project/schools/model/school"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { Subject } from "rxjs"; import { debounceTime, switchMap } from "rxjs/operators"; diff --git a/src/app/core/user/user.spec.ts b/src/app/core/user/user.spec.ts index 3c76a1bf63..731aee6c5b 100644 --- a/src/app/core/user/user.spec.ts +++ b/src/app/core/user/user.spec.ts @@ -17,7 +17,7 @@ import { User } from "./user"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { EntitySchemaService } from "../entity/schema/entity-schema.service"; describe("User", () => { diff --git a/src/app/core/user/user.ts b/src/app/core/user/user.ts index 1949e1cd4a..b573454cba 100644 --- a/src/app/core/user/user.ts +++ b/src/app/core/user/user.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DatabaseEntity } from "../entity/database-entity.decorator"; import { DatabaseField } from "../entity/database-field.decorator"; diff --git a/src/app/features/historical-data/demo-historical-data-generator.ts b/src/app/features/historical-data/demo-historical-data-generator.ts index ce1c789f87..0e24a28018 100644 --- a/src/app/features/historical-data/demo-historical-data-generator.ts +++ b/src/app/features/historical-data/demo-historical-data-generator.ts @@ -8,7 +8,7 @@ import { ConfigurableEnumConfig, } from "../../core/configurable-enum/configurable-enum.interface"; import { faker } from "../../core/demo-data/faker"; -import { ENTITY_CONFIG_PREFIX } from "../../core/entity/entity"; +import { ENTITY_CONFIG_PREFIX } from "../../core/entity/model/entity"; export class DemoHistoricalDataConfig { minCountAttributes: number; diff --git a/src/app/features/historical-data/historical-data.service.spec.ts b/src/app/features/historical-data/historical-data.service.spec.ts index 3ea26bfb57..e847b8347b 100644 --- a/src/app/features/historical-data/historical-data.service.spec.ts +++ b/src/app/features/historical-data/historical-data.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { HistoricalDataService } from "./historical-data.service"; import { EntityMapperService } from "../../core/entity/entity-mapper.service"; -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { HistoricalEntityData } from "./historical-entity-data"; import { expectEntitiesToMatch } from "../../utils/expect-entity-data.spec"; import { PouchDatabase } from "../../core/database/pouch-database"; diff --git a/src/app/features/historical-data/historical-data/historical-data.component.spec.ts b/src/app/features/historical-data/historical-data/historical-data.component.spec.ts index 0baed6c436..36f7ad3b3f 100644 --- a/src/app/features/historical-data/historical-data/historical-data.component.spec.ts +++ b/src/app/features/historical-data/historical-data/historical-data.component.spec.ts @@ -8,7 +8,7 @@ import { import { HistoricalDataComponent } from "./historical-data.component"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { HistoricalDataModule } from "../historical-data.module"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HistoricalEntityData } from "../historical-entity-data"; import moment from "moment"; import { DatePipe } from "@angular/common"; diff --git a/src/app/features/historical-data/historical-data/historical-data.component.ts b/src/app/features/historical-data/historical-data/historical-data.component.ts index 6352c7da2c..83321a80b0 100644 --- a/src/app/features/historical-data/historical-data/historical-data.component.ts +++ b/src/app/features/historical-data/historical-data/historical-data.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { HistoricalEntityData } from "../historical-entity-data"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HistoricalDataService } from "../historical-data.service"; import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; diff --git a/src/app/features/historical-data/historical-entity-data.ts b/src/app/features/historical-data/historical-entity-data.ts index 65fd8e1e3c..2480f8d1c7 100644 --- a/src/app/features/historical-data/historical-entity-data.ts +++ b/src/app/features/historical-data/historical-entity-data.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { DatabaseEntity } from "../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../core/entity/database-field.decorator"; diff --git a/src/app/features/reporting/query.service.ts b/src/app/features/reporting/query.service.ts index 3907e74f7d..814c87e18c 100644 --- a/src/app/features/reporting/query.service.ts +++ b/src/app/features/reporting/query.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity, EntityConstructor } from "../../core/entity/entity"; +import { Entity, EntityConstructor } from "../../core/entity/model/entity"; import { Child } from "../../child-dev-project/children/model/child"; import { School } from "../../child-dev-project/schools/model/school"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; diff --git a/src/app/utils/expect-entity-data.spec.ts b/src/app/utils/expect-entity-data.spec.ts index 6d1ca14ef7..c00d4e921a 100644 --- a/src/app/utils/expect-entity-data.spec.ts +++ b/src/app/utils/expect-entity-data.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from "@angular/core/testing"; import { EntitySchemaService } from "../core/entity/schema/entity-schema.service"; -import { Entity } from "../core/entity/entity"; +import { Entity } from "../core/entity/model/entity"; import { EntityMapperService } from "../core/entity/entity-mapper.service"; /** From 97adb6503047af63b48817ed99b251eca2409964 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 11:01:42 +0200 Subject: [PATCH 205/230] undone changes to warning level --- .../aser/demo-aser-generator.service.ts | 5 ++-- .../child-dev-project/aser/model/aser.spec.ts | 10 +++----- src/app/child-dev-project/aser/model/aser.ts | 12 +++------ .../attendance/model/activity-attendance.ts | 19 +++++++------- .../attendance/model/attendance-month.spec.ts | 6 ++--- .../attendance/model/attendance-month.ts | 11 ++++---- .../children-bmi-dashboard.component.ts | 5 ++-- .../health-checkup/model/health-check.ts | 11 ++++---- src/app/child-dev-project/notes/model/note.ts | 25 +++++++++++++------ 9 files changed, 50 insertions(+), 54 deletions(-) diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index 2790c1e57f..2c30824f9b 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -3,11 +3,11 @@ import { DemoDataGenerator } from "../../core/demo-data/demo-data-generator"; import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; -import { warningLevels } from "../warning-level"; import { Aser } from "./model/aser"; import { ConfigurableEnumValue } from "../../core/configurable-enum/configurable-enum.interface"; import { mathLevels } from "./model/mathLevels"; import { readingLevels } from "./model/readingLevels"; +import { WarningLevel } from "../../core/entity/model/warning-level"; /** * Generate ASER results every 12 months for each Child until passing. @@ -68,8 +68,7 @@ export class DemoAserGeneratorService extends DemoDataGenerator { previousResult = aserResult; } while ( date < faker.getEarlierDateOrToday(child.dropoutDate) && - previousResult.getWarningLevel() !== - warningLevels.find((level) => level.id === "OK") + previousResult.getWarningLevel() !== WarningLevel.OK ); return data; diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index 7237201afe..63ed13cebb 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -16,12 +16,12 @@ */ import { Aser } from "./aser"; -import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { mathLevels } from "./mathLevels"; import { readingLevels } from "./readingLevels"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; describe("Aser", () => { const ENTITY_TYPE = "Aser"; @@ -79,9 +79,7 @@ describe("Aser", () => { const id = "test1"; const entity = new Aser(id); - expect(entity.getWarningLevel()).toBe( - warningLevels.find((level) => level.id === "OK") - ); + expect(entity.getWarningLevel()).toBe(WarningLevel.OK); }); it("warning level WARNING if some bad results", function () { @@ -90,8 +88,6 @@ describe("Aser", () => { entity.english = readingLevels[1]; entity.math = readingLevels[2]; - expect(entity.getWarningLevel()).toBe( - warningLevels.find((level) => level.id === "WARNING") - ); + expect(entity.getWarningLevel()).toBe(WarningLevel.WARNING); }); }); diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index b836aa3c1e..86fb4b9c6c 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -16,12 +16,12 @@ */ import { Entity } from "../../../core/entity/model/entity"; -import { warningLevels } from "../../warning-level"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; import { mathLevels } from "./mathLevels"; import { readingLevels } from "./readingLevels"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; @DatabaseEntity("Aser") export class Aser extends Entity { @@ -69,20 +69,16 @@ export class Aser extends Entity { math: ConfigurableEnumValue; @DatabaseField({ label: "Remarks" }) remarks: string = ""; - getWarningLevel(): ConfigurableEnumValue { - let warningLevel; - + getWarningLevel(): WarningLevel { if ( Aser.isReadingPassedOrNA(this.english) && Aser.isReadingPassedOrNA(this.hindi) && Aser.isReadingPassedOrNA(this.bengali) && Aser.isMathPassedOrNA(this.math) ) { - warningLevel = warningLevels.find((level) => level.id === "OK"); + return WarningLevel.OK; } else { - warningLevel = warningLevels.find((level) => level.id === "WARNING"); + return WarningLevel.WARNING; } - - return warningLevel; } } diff --git a/src/app/child-dev-project/attendance/model/activity-attendance.ts b/src/app/child-dev-project/attendance/model/activity-attendance.ts index 906126cead..80d70d7b75 100644 --- a/src/app/child-dev-project/attendance/model/activity-attendance.ts +++ b/src/app/child-dev-project/attendance/model/activity-attendance.ts @@ -2,12 +2,11 @@ import { AttendanceLogicalStatus, AttendanceStatusType, } from "./attendance-status"; -import { Entity } from "../../../core/entity/model/entity"; import { RecurringActivity } from "./recurring-activity"; import { defaultAttendanceStatusTypes } from "../../../core/config/default-config/default-attendance-status-types"; -import { warningLevels } from "../../warning-level"; import { EventNote } from "./event-note"; -import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; +import { Entity } from "../../../core/entity/model/entity"; /** * Aggregate information about all events for a {@link RecurringActivity} within a given time period. @@ -102,14 +101,14 @@ export class ActivityAttendance extends Entity { return this.countIndividual(childId, AttendanceLogicalStatus.ABSENT); } - getAttendancePercentage(childId: string) { + getAttendancePercentage(childId: string): number { const present = this.countEventsPresent(childId); const absent = this.countEventsAbsent(childId); return present / (present + absent); } - getAttendancePercentageAverage() { + getAttendancePercentageAverage(): number { // TODO calculate overall averaged attendance percentage return NaN; } @@ -199,7 +198,7 @@ export class ActivityAttendance extends Entity { /** * Custom warning level for attendance thresholds - optionally for a specific child. */ - public getWarningLevel(forChildId?: string): ConfigurableEnumValue { + public getWarningLevel(forChildId?: string): WarningLevel { let attendancePercentage; if (forChildId) { attendancePercentage = this.getAttendancePercentage(forChildId); @@ -208,13 +207,13 @@ export class ActivityAttendance extends Entity { } if (!attendancePercentage) { - return warningLevels.find((level) => level.id === "OK"); + return WarningLevel.NONE; } else if (attendancePercentage < ActivityAttendance.THRESHOLD_URGENT) { - return warningLevels.find((level) => level.id === "URGENT"); + return WarningLevel.URGENT; } else if (attendancePercentage < ActivityAttendance.THRESHOLD_WARNING) { - return warningLevels.find((level) => level.id === "WARNING"); + return WarningLevel.WARNING; } else { - return warningLevels.find((level) => level.id === "OK"); + return WarningLevel.OK; } } } diff --git a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts index bfa28ef314..4393506d2f 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts @@ -16,10 +16,10 @@ */ import { AttendanceMonth, daysInMonth } from "./attendance-month"; -import { warningLevels } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; describe("AttendanceMonth", () => { const ENTITY_TYPE = "AttendanceMonth"; @@ -103,9 +103,7 @@ describe("AttendanceMonth", () => { entity.daysWorking = working; entity.daysAttended = attended; - expect(entity.getWarningLevel()).toBe( - warningLevels.find((level) => level.id === "URGENT") - ); + expect(entity.getWarningLevel()).toBe(WarningLevel.URGENT); }); it("has dailyRegister array after creation", () => { diff --git a/src/app/child-dev-project/attendance/model/attendance-month.ts b/src/app/child-dev-project/attendance/model/attendance-month.ts index f17b0dc1ef..bf0fbe58ff 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.ts @@ -16,12 +16,11 @@ */ import { Entity } from "../../../core/entity/model/entity"; -import { warningLevels } from "../../warning-level"; import { AttendanceDay } from "./attendance-day"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { AttendanceStatus } from "./attendance-status"; -import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * @deprecated Use new system based on EventNote and RecurrentActivity instead @@ -223,14 +222,14 @@ export class AttendanceMonth extends Entity { return this.daysAttended / (this.daysWorking - this.daysExcused); } - getWarningLevel(): ConfigurableEnumValue { + getWarningLevel(): WarningLevel { const attendance = this.getAttendancePercentage(); if (attendance < AttendanceMonth.THRESHOLD_URGENT) { - return warningLevels.find((level) => level.id === "URGENT"); + return WarningLevel.URGENT; } else if (attendance < AttendanceMonth.THRESHOLD_WARNING) { - return warningLevels.find((level) => level.id === "WARNING"); + return WarningLevel.WARNING; } else { - return warningLevels.find((level) => level.id === "OK"); + return WarningLevel.OK; } } } diff --git a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts index 933941a65b..651f7931e1 100644 --- a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts +++ b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { HealthCheck } from "../../health-checkup/model/health-check"; -import { warningLevels } from "../../warning-level"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { take } from "rxjs/operators"; import { ChildrenService } from "../children.service"; import { Child } from "../model/child"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; interface BmiRow { childId: string; @@ -53,8 +53,7 @@ export class ChildrenBmiDashboardComponent ); /**Check health status */ if ( - this.currentHealthCheck.getWarningLevel() === - warningLevels.find((level) => level.id === "URGENT") + this.currentHealthCheck.getWarningLevel() === WarningLevel.URGENT ) { this.bmiRows.push({ childId: child.getId(), diff --git a/src/app/child-dev-project/health-checkup/model/health-check.ts b/src/app/child-dev-project/health-checkup/model/health-check.ts index 8eca16bf91..1e471eb2f6 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.ts @@ -18,8 +18,7 @@ import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { warningLevels } from "../../warning-level"; -import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * Model Class for the Health Checks that are taken for a Child. @@ -50,13 +49,13 @@ export class HealthCheck extends Entity { return this.weight / ((this.height / 100) * (this.height / 100)); } - getWarningLevel(): ConfigurableEnumValue { + getWarningLevel(): WarningLevel { if (this.bmi <= 16 || this.bmi >= 30) { - return warningLevels.find((level) => level.id === "URGENT"); + return WarningLevel.URGENT; } else if (this.bmi >= 18 && this.bmi <= 25) { - return warningLevels.find((level) => level.id === "OK"); + return WarningLevel.OK; } else { - return warningLevels.find((level) => level.id === "WARNING"); + return WarningLevel.WARNING; } } } diff --git a/src/app/child-dev-project/notes/model/note.ts b/src/app/child-dev-project/notes/model/note.ts index eb6cfb0be5..66d70425ac 100644 --- a/src/app/child-dev-project/notes/model/note.ts +++ b/src/app/child-dev-project/notes/model/note.ts @@ -18,7 +18,6 @@ import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { Entity } from "../../../core/entity/model/entity"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { warningLevels } from "../../warning-level"; import { INTERACTION_TYPE_CONFIG_ID, InteractionType, @@ -31,6 +30,10 @@ import { import { User } from "../../../core/user/user"; import { Child } from "../../children/model/child"; import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { + getWarningLevelColor, + WarningLevel, +} from "../../../core/entity/model/warning-level"; @DatabaseEntity("Note") export class Note extends Entity { @@ -102,23 +105,31 @@ export class Note extends Entity { }) warningLevel: ConfigurableEnumValue; - getWarningLevel(): ConfigurableEnumValue { - return this.warningLevel || super.getWarningLevel(); + getWarningLevel(): WarningLevel { + if (this.warningLevel) { + return WarningLevel[this.warningLevel.id]; + } else { + return WarningLevel.NONE; + } } - // TODO: color logic should not be part of entity/model but rather in the component responsible for displaying it public getColor() { - return super.getColor() || this.category.color || ""; + const actualLevel = this.getWarningLevel(); + if (actualLevel === WarningLevel.OK || actualLevel === WarningLevel.NONE) { + return this.category.color; + } else { + return super.getColor(); + } } - public getColorForId(childId: string) { + public getColorForId(childId: string): string { if ( this.category.isMeeting && this.childrenAttendance.get(childId)?.status.countAs === AttendanceLogicalStatus.ABSENT ) { // child is absent, highlight the entry - return warningLevels.find((warning) => warning.id === "URGENT").color; + return getWarningLevelColor(WarningLevel.URGENT); } return this.getColor(); } From f6a8131fffc2d296f8119217d970531bac29bed9 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 11:20:41 +0200 Subject: [PATCH 206/230] made select migration less complex --- .../aser/model/mathLevels.ts | 10 +-- .../aser/model/readingLevels.ts | 10 +-- .../educational-material/model/materials.ts | 50 ++++++------ src/app/core/admin/admin/admin.component.ts | 3 - .../config/config-migration.service.spec.ts | 6 +- .../core/config/config-migration.service.ts | 6 +- .../configurable-enum-datatype.ts | 3 +- ...onfigurable-enum-migration.service.spec.ts | 80 ------------------- .../configurable-enum-migration.service.ts | 30 ------- 9 files changed, 40 insertions(+), 158 deletions(-) delete mode 100644 src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts delete mode 100644 src/app/core/configurable-enum/configurable-enum-migration.service.ts diff --git a/src/app/child-dev-project/aser/model/mathLevels.ts b/src/app/child-dev-project/aser/model/mathLevels.ts index 3dd4c5274a..dda86891a9 100644 --- a/src/app/child-dev-project/aser/model/mathLevels.ts +++ b/src/app/child-dev-project/aser/model/mathLevels.ts @@ -6,23 +6,23 @@ export const mathLevels: ConfigurableEnumValue[] = [ label: "", }, { - id: "nothing", + id: "Nothing", label: "Nothing", }, { - id: "numbers1to9", + id: "Numbers 1-9", label: "Numbers 1-9", }, { - id: "numbers10to99", + id: "Numbers 10-99", label: "Numbers 10-99", }, { - id: "subtraction", + id: "Subtraction", label: "Subtraction", }, { - id: "division", + id: "Division", label: "Division", }, ]; diff --git a/src/app/child-dev-project/aser/model/readingLevels.ts b/src/app/child-dev-project/aser/model/readingLevels.ts index bfa1cdd4ef..ffc2e7113e 100644 --- a/src/app/child-dev-project/aser/model/readingLevels.ts +++ b/src/app/child-dev-project/aser/model/readingLevels.ts @@ -6,23 +6,23 @@ export const readingLevels: ConfigurableEnumValue[] = [ label: "", }, { - id: "nothing", + id: "Nothing", label: "Nothing", }, { - id: "read_letters", + id: "Read Letters", label: "Read Letters", }, { - id: "read_words", + id: "Read Words", label: "Read Words", }, { - id: "read_sentence", + id: "Read Sentence", label: "Read Sentence", }, { - id: "read_paragraph", + id: "Read Paragraph", label: "Read Paragraph", }, ]; diff --git a/src/app/child-dev-project/educational-material/model/materials.ts b/src/app/child-dev-project/educational-material/model/materials.ts index e5c6d0a8ed..924559ac93 100644 --- a/src/app/child-dev-project/educational-material/model/materials.ts +++ b/src/app/child-dev-project/educational-material/model/materials.ts @@ -14,11 +14,11 @@ export const materials: ConfigurableEnumValue[] = [ label: "sharpener", }, { - id: "pen_black", + id: "pen (black)", label: "pen (black)", }, { - id: "oil_pastels", + id: "oil pastels", label: "oil pastels", }, { @@ -26,100 +26,100 @@ export const materials: ConfigurableEnumValue[] = [ label: "crayons", }, { - id: "sketch_pens", + id: "sketch pens", label: "sketch pens", }, { - id: "scale_big", + id: "scale (big)", label: "scale (big)", }, { - id: "scale_small", + id: "scale (small)", label: "scale (small)", }, { - id: "geometry_box", + id: "geometry box", label: "geometry box", }, { - id: "copy_single_small", + id: "copy (single line, small)", label: "copy (single line, small)", }, { - id: "copy_single_big", + id: "copy (single line, big)", label: "copy (single line, big)", }, { - id: "copy_four", + id: "copy (four line)", label: "copy (four line)", }, { - id: "copy_squared", + id: "copy (squared)", label: "copy (squared)", }, { - id: "copy_plain", + id: "copy (plain)", label: "copy (plain)", }, { - id: "copy_line_plain", + id: "copy (line-plain)", label: "copy (line-plain)", }, { - id: "copy_drawing", + id: "copy (drawing)", label: "copy (drawing)", }, { - id: "copy_practical", + id: "copy (practical)", label: "copy (practical)", }, { - id: "graph_book", + id: "graph book", label: "graph book", }, { - id: "project_papers", + id: "project papers", label: "project papers", }, { - id: "project_file", + id: "project file", label: "project file", }, { - id: "scrap_book", + id: "scrap book", label: "scrap book", }, { - id: "exam_board", + id: "exam board", label: "exam board", }, { - id: "bag", + id: "Bag", label: "Bag", color: "#B3E5FC", }, { - id: "school_uniform", + id: "School Uniform", label: "School Uniform", color: "#B3E5FC", }, { - id: "school_shoes", + id: "School Shoes", label: "School Shoes", color: "#B3E5FC", }, { - id: "sports_dress", + id: "Sports Dress", label: "Sports Dress", color: "#B3E5FC", }, { - id: "sports_shoes", + id: "Sports Shoes", label: "Sports Shoes", color: "#B3E5FC", }, { - id: "raincoat", + id: "Raincoat", label: "Raincoat", color: "#B3E5FC", }, diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index 43a5796819..428d593fe2 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -13,7 +13,6 @@ import { AttendanceMigrationService } from "../../../child-dev-project/attendanc import { NotesMigrationService } from "../../../child-dev-project/notes/notes-migration/notes-migration.service"; import { ChildrenMigrationService } from "../../../child-dev-project/children/child-photo-service/children-migration.service"; import { ConfigMigrationService } from "../../config/config-migration.service"; -import { ConfigurableEnumMigrationService } from "../../configurable-enum/configurable-enum-migration.service"; /** * Admin GUI giving administrative users different options/actions. @@ -45,7 +44,6 @@ export class AdminComponent implements OnInit { public notesMigration: NotesMigrationService, public childrenMigrationService: ChildrenMigrationService, public configMigrationService: ConfigMigrationService, - public configurableEnumMigrationSerivice: ConfigurableEnumMigrationService ) {} ngOnInit() { @@ -62,7 +60,6 @@ export class AdminComponent implements OnInit { async migrateConfigChanges() { await this.configMigrationService.migrateConfig(); - await this.configurableEnumMigrationSerivice.migrateSelectionsToConfigurableEnum(); } /** diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 5db4349cc7..08623156e4 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -450,15 +450,15 @@ const expectedStatusConfigurableEnum: ConfigurableEnumValue[] = [ label: "", }, { - id: "active", + id: "Active", label: "Active", }, { - id: "inactive", + id: "Inactive", label: "Inactive", }, { - id: "still_considering", + id: "Still Considering", label: "Still Considering", }, ]; diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 09bf234cc6..b7c9ea4176 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -304,11 +304,7 @@ export class ConfigMigrationService { ...formField["additional"].map((option: string) => { return { label: option, - id: option - .toLowerCase() - .replace("(", "") - .replace(")", "") - .replace(" ", "_"), + id: option, }; }) ); diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts index 11c7581451..e911d631f7 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.ts @@ -37,9 +37,8 @@ export class ConfigurableEnumDatatype enumId = CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId; } - // The label check is used to also match enums that were automatically created return this.configService .getConfig(enumId) - ?.find((option) => option.id === value || option.label === value); + ?.find((option) => option.id === value); } } diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts deleted file mode 100644 index 363a916459..0000000000 --- a/src/app/core/configurable-enum/configurable-enum-migration.service.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { TestBed } from "@angular/core/testing"; - -import { ConfigurableEnumMigrationService } from "./configurable-enum-migration.service"; -import { PouchDatabase } from "../database/pouch-database"; -import { EntityMapperService } from "../entity/entity-mapper.service"; -import { EntitySchemaService } from "../entity/schema/entity-schema.service"; -import { Database } from "../database/database"; -import { ConfigurableEnumModule } from "./configurable-enum.module"; - -describe("ConfigurableEnumMigrationService", () => { - let service: ConfigurableEnumMigrationService; - let database: PouchDatabase; - - beforeEach(() => { - database = PouchDatabase.createWithInMemoryDB(); - TestBed.configureTestingModule({ - imports: [ConfigurableEnumModule], - providers: [ - EntityMapperService, - EntitySchemaService, - { provide: Database, useValue: database }, - ], - }); - service = TestBed.inject(ConfigurableEnumMigrationService); - }); - - afterEach(async () => { - await database.destroy(); - }); - - it("should be created", () => { - expect(service).toBeTruthy(); - }); - - it("should migrate aser entities", async () => { - const oldAser = { - _id: "Aser:1", - child: "childId", - date: new Date(), - hindi: "Nothing", - bengali: "Read Letters", - english: "Read Words", - math: "Numbers 1-9", - remarks: "some remarks", - }; - await database.put(oldAser); - - await service.migrateSelectionsToConfigurableEnum(); - const newAser = await database.get("Aser:1"); - - expect(newAser["child"]).toBe(oldAser.child); - expect(newAser["hindi"]).toBe("nothing"); - expect(newAser["bengali"]).toBe("read_letters"); - expect(newAser["english"]).toBe("read_words"); - expect(newAser["math"]).toBe("numbers1to9"); - expect(new Date(newAser["date"])).toEqual(oldAser.date); - expect(newAser["remarks"]).toBe(oldAser.remarks); - }); - - it("should migrate education material entities", async () => { - const oldMaterial = { - _id: "EducationalMaterial:1", - child: "childId", - date: new Date(), - materialType: "pen (black)", - materialAmount: 2, - description: "some description", - }; - await database.put(oldMaterial); - - await service.migrateSelectionsToConfigurableEnum(); - const newMaterial = await database.get("EducationalMaterial:1"); - - expect(newMaterial["child"]).toBe(oldMaterial.child); - expect(new Date(newMaterial["date"])).toEqual(oldMaterial.date); - expect(newMaterial["materialType"]).toBe("pen_black"); - expect(newMaterial["materialAmount"]).toBe(oldMaterial.materialAmount); - expect(newMaterial["description"]).toBe(oldMaterial.description); - }); -}); diff --git a/src/app/core/configurable-enum/configurable-enum-migration.service.ts b/src/app/core/configurable-enum/configurable-enum-migration.service.ts deleted file mode 100644 index 552b649d3a..0000000000 --- a/src/app/core/configurable-enum/configurable-enum-migration.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from "@angular/core"; -import { EntityMapperService } from "../entity/entity-mapper.service"; -import { EducationalMaterial } from "../../child-dev-project/educational-material/model/educational-material"; -import { Aser } from "../../child-dev-project/aser/model/aser"; -import { Entity } from "../entity/model/entity"; -import { Child } from "../../child-dev-project/children/model/child"; -import { Note } from "../../child-dev-project/notes/model/note"; - -@Injectable({ - providedIn: "root", -}) -export class ConfigurableEnumMigrationService { - constructor(private entityMapper: EntityMapperService) {} - - async migrateSelectionsToConfigurableEnum(): Promise { - const entitiesToMigrate: typeof Entity[] = [ - Aser, - EducationalMaterial, - Child, - Note, - ]; - for (const entityConstructor of entitiesToMigrate) { - const entities = await this.entityMapper.loadType(entityConstructor); - // The entities will automatically be saved correctly once the schema is applied - await Promise.all( - entities.map((entity) => this.entityMapper.save(entity)) - ); - } - } -} From bd84a4d0cc2dd2f34f91d608c2259e907cba39ec Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 11:36:36 +0200 Subject: [PATCH 207/230] adapted warning levels for note details --- .../notes/demo-data/demo-note-generator.service.ts | 2 +- .../notes/demo-data/notes_group-stories.ts | 2 +- .../notes/demo-data/notes_individual-stories.ts | 2 +- src/app/child-dev-project/notes/model/note.spec.ts | 2 +- .../notes/note-details/note-details.component.html | 9 ++++++--- .../notes/notes-manager/notes-manager.component.ts | 2 +- .../{warning-level.ts => warning-levels.ts} | 12 ++++-------- src/app/core/config/config-fix.ts | 2 +- src/app/core/entity/model/entity.ts | 2 +- src/app/core/entity/model/warning-level.ts | 2 +- 10 files changed, 18 insertions(+), 19 deletions(-) rename src/app/child-dev-project/{warning-level.ts => warning-levels.ts} (60%) diff --git a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts index b1fbbc331d..d6bc4f1412 100644 --- a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts +++ b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts @@ -4,7 +4,7 @@ import { Injectable } from "@angular/core"; import { Child } from "../../children/model/child"; import { Note } from "../model/note"; import { faker } from "../../../core/demo-data/faker"; -import { warningLevels } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; import { noteIndividualStories } from "./notes_individual-stories"; import { noteGroupStories } from "./notes_group-stories"; import { centersUnique } from "../../children/demo-data-generators/fixtures/centers"; diff --git a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts index 598447a6e7..34b231daeb 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts @@ -1,4 +1,4 @@ -import { warningLevels } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; export const noteGroupStories = [ { diff --git a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts index 164a10ce68..a630c3cf5c 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts @@ -1,4 +1,4 @@ -import { warningLevels } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; export const noteIndividualStories = [ { diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index 25fdc10595..a478ec0342 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -1,5 +1,5 @@ import { Note } from "./note"; -import { warningLevels } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { Entity } from "../../../core/entity/model/entity"; diff --git a/src/app/child-dev-project/notes/note-details/note-details.component.html b/src/app/child-dev-project/notes/note-details/note-details.component.html index e4424a4123..799ea46d80 100644 --- a/src/app/child-dev-project/notes/note-details/note-details.component.html +++ b/src/app/child-dev-project/notes/note-details/note-details.component.html @@ -47,9 +47,12 @@

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}

Status - Solved - Needs Follow-Up - Urgent Follow-Up + + {{ warningLevel.label }} +
diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts index 4c2fd75632..44c0842da2 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts @@ -3,7 +3,7 @@ import { Note } from "../model/note"; import { MediaObserver } from "@angular/flex-layout"; import { NoteDetailsComponent } from "../note-details/note-details.component"; import { ActivatedRoute } from "@angular/router"; -import { warningLevels } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; import { FilterSelectionOption } from "../../../core/filter/filter-selection/filter-selection"; import { SessionService } from "../../../core/session/session-service/session.service"; diff --git a/src/app/child-dev-project/warning-level.ts b/src/app/child-dev-project/warning-levels.ts similarity index 60% rename from src/app/child-dev-project/warning-level.ts rename to src/app/child-dev-project/warning-levels.ts index c319e6db39..3c93235ee4 100644 --- a/src/app/child-dev-project/warning-level.ts +++ b/src/app/child-dev-project/warning-levels.ts @@ -3,22 +3,18 @@ import { ConfigurableEnumValue } from "../core/configurable-enum/configurable-en export const warningLevels: ConfigurableEnumValue[] = [ { id: "", - label: "None", - color: "", + label: "", }, { id: "OK", - label: "OK", - color: "#90ee9040", + label: "Solved", }, { id: "WARNING", - label: "WARNING", - color: "#ffa50080", + label: "Needs Follow-Up", }, { id: "URGENT", - label: "URGENT", - color: "#fd727280", + label: "Urgent Follow-Up", }, ]; diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 656ae24069..82d3ca7632 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -8,7 +8,7 @@ import { genders } from "../../child-dev-project/children/model/genders"; import { materials } from "../../child-dev-project/educational-material/model/materials"; import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; -import { warningLevels } from "../../child-dev-project/warning-level"; +import { warningLevels } from "../../child-dev-project/warning-levels"; import { ratingAnswers } from "../../features/historical-data/rating-answers"; // prettier-ignore diff --git a/src/app/core/entity/model/entity.ts b/src/app/core/entity/model/entity.ts index 4a951ea1e7..6a7c10cc4b 100644 --- a/src/app/core/entity/model/entity.ts +++ b/src/app/core/entity/model/entity.ts @@ -211,7 +211,7 @@ export class Entity { * and highlighted in generic components of the UI. */ public getWarningLevel(): WarningLevel { - return WarningLevel.OK; + return WarningLevel.NONE; } /** diff --git a/src/app/core/entity/model/warning-level.ts b/src/app/core/entity/model/warning-level.ts index f93225f730..c90c3d9569 100644 --- a/src/app/core/entity/model/warning-level.ts +++ b/src/app/core/entity/model/warning-level.ts @@ -14,6 +14,6 @@ export function getWarningLevelColor(warningLevel: WarningLevel) { case WarningLevel.OK: return "#90ee9040"; default: - return "#ffa50080"; + return ""; } } From 4d0da85a9b684d6df666590bf3766210a00aa348 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 11:55:32 +0200 Subject: [PATCH 208/230] entity copy is moved into the form service --- .../entity-form/entity-form.service.spec.ts | 1 + .../entity-form/entity-form.service.ts | 12 +++++++----- .../entity-subrecord/entity-subrecord.component.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index c2edb79bba..fa807d40b6 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -31,6 +31,7 @@ describe("EntityFormService", () => { it("should not save invalid entities", () => { const entity = new Entity("initialId"); + spyOn(entity, "copy").and.returnValue(entity); spyOn(entity, "assertValid").and.throwError(new Error()); const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 882bd99044..e9a3f97d17 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -74,18 +74,20 @@ export class EntityFormService { /** * This function applies the changes of the formGroup to the entity. * If the form is invalid or the entity does not pass validation after applying the changes, an error will be thrown. - * In order to not edit the initial entity until the new one is saved, call entity.copy() on the input entity. + * The input entity will not be modified but a copy of it will be returned in case of success. * @param form The formGroup holding the changes - * @param entity The entity on which the changes should be applied. Should be a copy. + * @param entity The entity on which the changes should be applied. + * @returns a copy of the input entity with the changes from the form group */ public saveChanges(form: FormGroup, entity: T): Promise { this.checkFormValidity(form); - this.assignFormValuesToEntity(form, entity); - entity.assertValid(); + const entityCopy = entity.copy() as T; + this.assignFormValuesToEntity(form, entityCopy); + entityCopy.assertValid(); return this.entityMapper .save(entity) - .then(() => entity) + .then(() => entityCopy) .catch((err) => { throw new Error(`Could not save ${entity.getType()}: ${err}`); }); diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 793803c70d..5cc91b59db 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -208,7 +208,7 @@ export class EntitySubrecordComponent implements OnChanges { try { row.record = await this.entityFormService.saveChanges( row.formGroup, - row.record.copy() as T + row.record ); row.formGroup.disable(); } catch (err) { From 403e6d7a91b2cd1db419dd600fc4bbff2ae5c552 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 12:13:03 +0200 Subject: [PATCH 209/230] fixed tests --- .../notes/model/note.spec.ts | 10 +++++--- .../entity-form/entity-form.service.ts | 2 +- .../entity-form/entity-form.component.spec.ts | 25 +++++++------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index a478ec0342..4d583ac9ea 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -19,6 +19,10 @@ import { ConfigurableEnumConfig, } from "../../../core/configurable-enum/configurable-enum.interface"; import { createTestingConfigService } from "../../../core/config/config.service"; +import { + getWarningLevelColor, + WarningLevel, +} from "../../../core/entity/model/warning-level"; const testStatusTypes: ConfigurableEnumConfig = [ { @@ -158,12 +162,12 @@ describe("Note", () => { it("should return colors", function () { const note = new Note("1"); + note.category = { id: "", label: "test", color: "#FFFFFF" }; expect(note.getColor()).toBe("#FFFFFF"); + note.warningLevel = warningLevels.find((level) => level.id === "URGENT"); - expect(note.getColor()).toBe( - warningLevels.find((level) => level.id === "URGENT").color - ); + expect(note.getColor()).toBe(getWarningLevelColor(WarningLevel.URGENT)); }); it("transforms interactionType from config", function () { diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index e9a3f97d17..e8f882c1a2 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -86,7 +86,7 @@ export class EntityFormService { entityCopy.assertValid(); return this.entityMapper - .save(entity) + .save(entityCopy) .then(() => entityCopy) .catch((err) => { throw new Error(`Could not save ${entity.getType()}: ${err}`); diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts index 9812f1e362..8daaf1657d 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts @@ -16,6 +16,7 @@ import { Child } from "../../../../child-dev-project/children/model/child"; import { EntityFormModule } from "../entity-form.module"; import { FormBuilder } from "@angular/forms"; import { MatSnackBarModule } from "@angular/material/snack-bar"; +import { EntityFormService } from "../entity-form.service"; describe("EntityFormComponent", () => { let component: EntityFormComponent; @@ -84,7 +85,7 @@ describe("EntityFormComponent", () => { it("should emit notification when a child is saved", (done) => { spyOnProperty(component.form, "valid").and.returnValue(true); const subscription = component.onSave.subscribe((child) => { - expect(child).toBe(testChild); + expect(child).toEqual(testChild); subscription.unsubscribe(); done(); }); @@ -92,25 +93,17 @@ describe("EntityFormComponent", () => { component.save(); }); - it("reports error when form is invalid", async () => { - const alertService = fixture.debugElement.injector.get(AlertService); + it("should show an warning alert when form service rejects saving", async () => { + const alertService = TestBed.inject(AlertService); spyOn(alertService, "addWarning"); - spyOnProperty(component.form, "invalid").and.returnValue(true); + const entityFormService = TestBed.inject(EntityFormService); + spyOn(entityFormService, "saveChanges").and.rejectWith( + new Error("error message") + ); await component.save(); - expect(alertService.addWarning).toHaveBeenCalled(); - }); - - it("logs error when saving fails", async () => { - const alertService = fixture.debugElement.injector.get(AlertService); - spyOn(alertService, "addWarning"); - spyOnProperty(component.form, "valid").and.returnValue(true); - mockEntityMapper.save.and.rejectWith(); - - await component.save(); - - expect(alertService.addWarning).toHaveBeenCalled(); + expect(alertService.addWarning).toHaveBeenCalledWith("error message"); }); it("should add column definitions from property schema", () => { From 8b85091a7478c567f4e20005eb5b42e4596a93f2 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 12:55:43 +0200 Subject: [PATCH 210/230] fixed prettier --- src/app/core/admin/admin/admin.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index 428d593fe2..b458f5d425 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -43,7 +43,7 @@ export class AdminComponent implements OnInit { public attendanceMigration: AttendanceMigrationService, public notesMigration: NotesMigrationService, public childrenMigrationService: ChildrenMigrationService, - public configMigrationService: ConfigMigrationService, + public configMigrationService: ConfigMigrationService ) {} ngOnInit() { From f0ca8aab0968dc451552e32ea52016a3317de266 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 13:37:01 +0200 Subject: [PATCH 211/230] fixed bug when migrating genders --- src/app/core/config/config-migration.service.spec.ts | 9 +++++++++ src/app/core/config/config-migration.service.ts | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 08623156e4..8b779f0736 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -46,6 +46,11 @@ describe("ConfigMigrationService", () => { title: "School", id: "schoolId", }, + { + component: "DisplayText", + title: "Gender", + id: "gender", + }, { component: "RecentAttendanceBlocks", title: "Attendance (School)", @@ -363,6 +368,10 @@ const expectedChildrenListConfig = { additional: "School", noSorting: true, }, + { + title: "Gender", + id: "gender", + }, { view: "RecentAttendanceBlocks", label: "Attendance (School)", diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index b7c9ea4176..19e60545d8 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -31,6 +31,7 @@ import { CONFIGURABLE_ENUM_CONFIG_PREFIX, ConfigurableEnumValue, } from "../configurable-enum/configurable-enum.interface"; +import { warningLevels } from "../../child-dev-project/warning-levels"; @Injectable({ providedIn: "root", @@ -66,6 +67,9 @@ export class ConfigMigrationService { ] = mathLevels; this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "genders"] = genders; this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "materials"] = materials; + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "warning-levels" + ] = warningLevels; } private migrateViewConfigs() { @@ -134,6 +138,12 @@ export class ConfigMigrationService { column.additional = "Child"; column.noSorting = true; } + const propertySchema = entity.schema.get(column.id); + if (propertySchema?.dataType === "configurable-enum") { + delete column.view; + delete column.edit; + delete column.additional; + } this.addLabelToEntity(column.label, column.id, entity, "short"); } catch (e) { console.warn(`Failed to migrate column ${column.id}: ${e}`); From 4dfca83dca2faaba62c3884854727c8a31af7232 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Jun 2021 13:49:50 +0200 Subject: [PATCH 212/230] fixed bug in filter functions --- .../notes-manager/notes-manager.component.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts index 44c0842da2..9ce04fc31f 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts @@ -1,9 +1,8 @@ -import { Component, OnInit, ViewChild } from "@angular/core"; +import { Component, Input, OnInit, ViewChild } from "@angular/core"; import { Note } from "../model/note"; import { MediaObserver } from "@angular/flex-layout"; import { NoteDetailsComponent } from "../note-details/note-details.component"; import { ActivatedRoute } from "@angular/router"; -import { warningLevels } from "../../warning-levels"; import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; import { FilterSelectionOption } from "../../../core/filter/filter-selection/filter-selection"; import { SessionService } from "../../../core/session/session-service/session.service"; @@ -13,9 +12,9 @@ import { LoggingService } from "../../../core/logging/logging.service"; import { EntityListComponent } from "../../../core/entity-components/entity-list/entity-list.component"; import { applyUpdate } from "../../../core/entity/model/entity-update"; import { EntityListConfig } from "../../../core/entity-components/entity-list/EntityListConfig"; -import { Input } from "@angular/core"; import { EventNote } from "../../attendance/model/event-note"; import { EntityConstructor } from "../../../core/entity/model/entity"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * additional config specifically for NotesManagerComponent @@ -44,25 +43,18 @@ export class NotesManagerComponent implements OnInit { noteConstructor = Note; notes: Note[] = []; - private readonly urgentLevel = warningLevels.find( - (level) => level.id === "URGENT" - ); - private readonly warningLevel = warningLevels.find( - (level) => level.id === "WARNING" - ); - private statusFS: FilterSelectionOption[] = [ { key: "urgent", label: "Urgent", - filterFun: (n: Note) => n.warningLevel === this.urgentLevel, + filterFun: (n: Note) => n.getWarningLevel() === WarningLevel.URGENT, }, { key: "follow-up", label: "Needs Follow-Up", filterFun: (n: Note) => - n.warningLevel === this.warningLevel || - n.warningLevel === this.urgentLevel, + n.getWarningLevel() === WarningLevel.URGENT || + n.getWarningLevel() === WarningLevel.WARNING, }, { key: "", label: "All", filterFun: () => true }, ]; From a45e6c0f1d4bc77bf7a17824e3ad34989ee91915 Mon Sep 17 00:00:00 2001 From: Simon <33730997+TheSlimvReal@users.noreply.github.com> Date: Wed, 30 Jun 2021 15:39:25 +0200 Subject: [PATCH 213/230] Connect Datatype Review Improvements (#866) * refactored validation function * fixed unit tests * added tests for entity validation * refactored reading and math levels * refactored gender as configurable enum * refactored material types * added migrations for the new configurable enums * added test for ensuring that the new enums are available * made warning level configurable enum * added migration for input select * removed edit selectable component * fix wrong selector name * added edit number component * added boolean datatype * applied changes according to the review * cleaned up display entity array component * added pipe to reduce change detection cycles * fixed tests * fixed error message when no edit component is defined * fixed prettier * fixed property assignment problem * added further documentation * opening details popup in edit mode * overworked saving process of popups * fixed some runtime problems * fixed failing tests * some minor fixes * undoing warning-level changes * undone changes to warning level * made select migration less complex * adapted warning levels for note details * entity copy is moved into the form service * fixed tests * fixed prettier * add warning-level config migration * fix notes follow-up filter Co-authored-by: Sebastian Leidig --- .../aser/demo-aser-generator.service.ts | 19 +-- .../child-dev-project/aser/model/aser.spec.ts | 18 +-- src/app/child-dev-project/aser/model/aser.ts | 69 ++++------ .../aser/model/mathLevels.ts | 28 ++++ .../aser/model/readingLevels.ts | 28 ++++ .../attendance-calendar.component.ts | 2 +- .../attendance/model/activity-attendance.ts | 8 +- .../attendance/model/attendance-month.spec.ts | 4 +- .../attendance/model/attendance-month.ts | 6 +- .../attendance/model/event-note.spec.ts | 2 +- .../model/recurring-activity.spec.ts | 2 +- .../attendance/model/recurring-activity.ts | 6 +- .../datatype-photo.spec.ts | 2 +- .../child-photo-service/datatype-photo.ts | 2 +- .../children-bmi-dashboard.component.ts | 4 +- .../children/children.service.spec.ts | 8 +- .../demo-child-generator.service.ts | 4 +- .../children/model/Gender.ts | 4 - .../children/model/child.spec.ts | 8 +- .../child-dev-project/children/model/child.ts | 10 +- .../model/childSchoolRelation.spec.ts | 42 +++--- .../children/model/childSchoolRelation.ts | 37 +++-- .../children/model/genders.ts | 16 +++ ...-educational-material-generator.service.ts | 7 +- .../educational-material.component.html | 2 +- .../educational-material.component.ts | 23 ++-- .../model/educational-material.spec.ts | 5 +- .../model/educational-material.ts | 53 +------- .../educational-material/model/materials.ts | 126 ++++++++++++++++++ .../health-checkup.stories.ts | 5 +- .../health-checkup/model/health-check.spec.ts | 2 +- .../health-checkup/model/health-check.ts | 6 +- .../demo-data/demo-note-generator.service.ts | 4 +- .../notes/demo-data/notes_group-stories.ts | 12 +- .../demo-data/notes_individual-stories.ts | 26 ++-- .../notes/model/note.spec.ts | 19 ++- src/app/child-dev-project/notes/model/note.ts | 39 +++--- .../note-details/note-details.component.html | 15 ++- .../note-details/note-details.component.ts | 2 +- .../notes-manager.component.spec.ts | 2 +- .../notes-manager/notes-manager.component.ts | 15 +-- .../progress-dashboard-config.spec.ts | 2 +- .../progress-dashboard-config.ts | 2 +- .../schools/model/school.spec.ts | 2 +- .../child-dev-project/schools/model/school.ts | 9 +- src/app/child-dev-project/warning-levels.ts | 20 +++ .../conflict-resolution-list.component.ts | 2 +- src/app/core/admin/admin/admin.component.html | 2 +- src/app/core/admin/admin/admin.component.ts | 4 + src/app/core/config/config-fix.ts | 25 ++-- .../config/config-migration.service.spec.ts | 79 ++++++++++- .../core/config/config-migration.service.ts | 79 ++++++++++- src/app/core/config/config.ts | 2 +- .../configurable-enum-datatype.spec.ts | 2 +- .../configurable-enum.interface.ts | 5 + .../configurable-enum.module.ts | 26 +++- ...isplay-configurable-enum.component.spec.ts | 2 +- .../display-configurable-enum.component.ts | 2 +- .../edit-configurable-enum.component.html | 0 .../edit-configurable-enum.component.scss | 0 .../edit-configurable-enum.component.spec.ts | 4 +- .../edit-configurable-enum.component.ts | 7 +- src/app/core/database/query-data-source.ts | 2 +- src/app/core/demo-data/demo-data-generator.ts | 2 +- .../entity-details/EntityDetailsConfig.ts | 59 +++++++- .../entity-details.component.spec.ts | 4 +- .../entity-details.component.ts | 6 +- .../form/form.component.spec.ts | 2 +- .../entity-details/form/form.component.ts | 24 +++- .../entity-form/entity-form.service.spec.ts | 19 +++ .../entity-form/entity-form.service.ts | 42 ++++-- .../entity-form/entity-form/FormConfig.ts | 57 +++++++- .../entity-form/entity-form.component.spec.ts | 27 ++-- .../entity-form/entity-form.component.ts | 56 +++++++- .../entity-form/entity-form.stories.ts | 15 +-- .../entity-list/EntityListConfig.ts | 2 +- .../entity-list/entity-list.component.spec.ts | 2 +- .../entity-list/entity-list.component.ts | 37 +++-- .../entity-list/filter-component.settings.ts | 28 ++++ .../entity-list/filter-generator.service.ts | 10 +- .../list-filter/list-filter.component.ts | 2 +- .../entity-subrecord.component.html | 2 +- .../entity-subrecord.component.spec.ts | 32 ++--- .../entity-subrecord.component.ts | 55 +++++--- .../list-paginator.component.ts | 2 +- .../dynamic-form-components/edit-component.ts | 37 +++++ .../edit-entity-array.component.ts | 4 +- .../edit-number/edit-number.component.html | 14 ++ .../edit-number.component.scss} | 0 .../edit-number/edit-number.component.spec.ts | 50 +++++++ .../edit-number/edit-number.component.ts | 20 +++ .../edit-percentage.component.html | 9 +- .../edit-selectable.component.html | 14 -- .../edit-selectable.component.spec.ts | 33 ----- .../edit-selectable.component.ts | 16 --- .../edit-single-entity.component.ts | 2 +- .../entity-select.component.spec.ts | 2 +- .../entity-select/entity-select.component.ts | 2 +- .../entity-utils/entity-utils.module.ts | 14 +- .../display-entity-array.component.html | 4 +- .../display-entity-array.component.spec.ts | 2 + .../display-entity-array.component.ts | 25 ++-- .../display-entity.component.ts | 2 +- .../entity-function.pipe.spec.ts | 8 ++ .../readonly-function/entity-function.pipe.ts | 15 +++ .../readonly-function.component.html | 2 +- .../readonly-function.component.spec.ts | 3 +- .../readonly-function.component.ts | 3 +- .../view-components/view-component.ts | 2 +- .../entity/database-field.decorator.spec.ts | 2 +- .../database-indexing.service.ts | 2 +- .../core/entity/entity-config.service.spec.ts | 2 +- src/app/core/entity/entity-config.service.ts | 2 +- .../core/entity/entity-mapper.service.spec.ts | 2 +- src/app/core/entity/entity-mapper.service.ts | 4 +- .../core/entity/mock-entity-mapper-service.ts | 4 +- .../entity/{ => model}/entity-update.spec.ts | 0 .../core/entity/{ => model}/entity-update.ts | 0 .../core/entity/{ => model}/entity.spec.ts | 4 +- src/app/core/entity/{ => model}/entity.ts | 25 ++-- .../entity/model}/warning-level.ts | 8 +- .../schema-datatypes/datatype-boolean.ts | 11 ++ .../schema-datatypes/datatype-map.spec.ts | 2 +- .../schema-datatypes/datatype-number.ts | 2 +- .../datatype-schema-embed.spec.ts | 2 +- .../schema-datatypes/datatype-schema-embed.ts | 2 +- .../entity/schema/entity-schema-datatype.ts | 2 +- .../core/entity/schema/entity-schema-field.ts | 16 +++ .../schema/entity-schema.service.spec.ts | 2 +- .../entity/schema/entity-schema.service.ts | 4 +- .../form-dialog-wrapper.component.ts | 2 +- .../form-dialog/form-dialog.service.spec.ts | 2 +- .../core/form-dialog/form-dialog.service.ts | 2 +- .../form-dialog/shows-entity.interface.ts | 2 +- .../changelog/changelog.component.spec.ts | 8 +- ...disable-entity-operation.directive.spec.ts | 2 +- .../disable-entity-operation.directive.ts | 2 +- .../entity-permissions.service.spec.ts | 2 +- .../permissions/entity-permissions.service.ts | 2 +- src/app/core/ui/search/search.component.ts | 2 +- src/app/core/user/user.spec.ts | 2 +- src/app/core/user/user.ts | 2 +- src/app/core/view/dynamic-components-map.ts | 8 +- .../demo-historical-data-generator.ts | 2 +- .../historical-data.service.spec.ts | 2 +- .../historical-data.component.spec.ts | 2 +- .../historical-data.component.ts | 2 +- .../historical-data/historical-entity-data.ts | 2 +- .../features/reporting/query.service.spec.ts | 22 +-- src/app/features/reporting/query.service.ts | 2 +- .../reporting/reporting.service.spec.ts | 76 +++++------ .../reporting/reporting/reporting.stories.ts | 7 +- src/app/utils/expect-entity-data.spec.ts | 2 +- 153 files changed, 1325 insertions(+), 668 deletions(-) create mode 100644 src/app/child-dev-project/aser/model/mathLevels.ts create mode 100644 src/app/child-dev-project/aser/model/readingLevels.ts delete mode 100644 src/app/child-dev-project/children/model/Gender.ts create mode 100644 src/app/child-dev-project/children/model/genders.ts create mode 100644 src/app/child-dev-project/educational-material/model/materials.ts create mode 100644 src/app/child-dev-project/warning-levels.ts rename src/app/core/{entity-components/entity-utils/view-components => configurable-enum}/display-configurable-enum/display-configurable-enum.component.spec.ts (93%) rename src/app/core/{entity-components/entity-utils/view-components => configurable-enum}/display-configurable-enum/display-configurable-enum.component.ts (73%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.html (100%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.scss (100%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.spec.ts (89%) rename src/app/core/{entity-components/entity-utils/dynamic-form-components => configurable-enum}/edit-configurable-enum/edit-configurable-enum.component.ts (72%) create mode 100644 src/app/core/entity-components/entity-list/filter-component.settings.ts create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html rename src/app/core/entity-components/entity-utils/dynamic-form-components/{edit-selectable/edit-selectable.component.scss => edit-number/edit-number.component.scss} (100%) create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts create mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts delete mode 100644 src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts create mode 100644 src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts create mode 100644 src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts rename src/app/core/entity/{ => model}/entity-update.spec.ts (100%) rename src/app/core/entity/{ => model}/entity-update.ts (100%) rename src/app/core/entity/{ => model}/entity.spec.ts (96%) rename src/app/core/entity/{ => model}/entity.ts (94%) rename src/app/{child-dev-project => core/entity/model}/warning-level.ts (81%) create mode 100644 src/app/core/entity/schema-datatypes/datatype-boolean.ts diff --git a/src/app/child-dev-project/aser/demo-aser-generator.service.ts b/src/app/child-dev-project/aser/demo-aser-generator.service.ts index e42c10bd37..2c30824f9b 100644 --- a/src/app/child-dev-project/aser/demo-aser-generator.service.ts +++ b/src/app/child-dev-project/aser/demo-aser-generator.service.ts @@ -3,8 +3,11 @@ import { DemoDataGenerator } from "../../core/demo-data/demo-data-generator"; import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; -import { WarningLevel } from "../warning-level"; import { Aser } from "./model/aser"; +import { ConfigurableEnumValue } from "../../core/configurable-enum/configurable-enum.interface"; +import { mathLevels } from "./model/mathLevels"; +import { readingLevels } from "./model/readingLevels"; +import { WarningLevel } from "../../core/entity/model/warning-level"; /** * Generate ASER results every 12 months for each Child until passing. @@ -47,15 +50,15 @@ export class DemoAserGeneratorService extends DemoDataGenerator { aserResult.child = child.getId(); aserResult.date = date; aserResult.math = this.selectNextSkillLevel( - Aser.MathLevels, + mathLevels.slice(1), previousResult.math ); aserResult.english = this.selectNextSkillLevel( - Aser.ReadingLevels, + readingLevels.slice(1), previousResult.english ); aserResult[firstLanguage] = this.selectNextSkillLevel( - Aser.ReadingLevels, + readingLevels.slice(1), previousResult[firstLanguage] ); @@ -73,13 +76,13 @@ export class DemoAserGeneratorService extends DemoDataGenerator { /** * Randomly select the next Aser level for a skill based on the previous result. - * @param skillRange The array of skill levels for the desired subject (Aser.MathLevels or Aser.ReadingLevels) + * @param skillRange The array of skill levels for the desired subject (mathLevels or readingLevels) * @param previousSkillLevel The string indicating the level from the previous test for this subject */ private selectNextSkillLevel( - skillRange: string[], - previousSkillLevel: string - ): string { + skillRange: ConfigurableEnumValue[], + previousSkillLevel: ConfigurableEnumValue + ): ConfigurableEnumValue { const previousSkillLevelIndex = skillRange.indexOf(previousSkillLevel); let nextSkillLevelIndex; diff --git a/src/app/child-dev-project/aser/model/aser.spec.ts b/src/app/child-dev-project/aser/model/aser.spec.ts index a58e5f4463..63ed13cebb 100644 --- a/src/app/child-dev-project/aser/model/aser.spec.ts +++ b/src/app/child-dev-project/aser/model/aser.spec.ts @@ -16,10 +16,12 @@ */ import { Aser } from "./aser"; -import { WarningLevel } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { mathLevels } from "./mathLevels"; +import { readingLevels } from "./readingLevels"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; describe("Aser", () => { const ENTITY_TYPE = "Aser"; @@ -50,10 +52,10 @@ describe("Aser", () => { child: "1", date: new Date(), - hindi: "Read Sentence", - bengali: "Nothing", - english: "Read Letters", - math: "Subtraction", + hindi: readingLevels[2], + bengali: readingLevels[1], + english: readingLevels[2], + math: mathLevels[4], remarks: "nothing to remark", searchIndices: [], @@ -83,8 +85,8 @@ describe("Aser", () => { it("warning level WARNING if some bad results", function () { const id = "test1"; const entity = new Aser(id); - entity.english = Aser.ReadingLevels[0]; - entity.math = Aser.MathLevels[1]; + entity.english = readingLevels[1]; + entity.math = readingLevels[2]; expect(entity.getWarningLevel()).toBe(WarningLevel.WARNING); }); diff --git a/src/app/child-dev-project/aser/model/aser.ts b/src/app/child-dev-project/aser/model/aser.ts index be68c026f3..86fb4b9c6c 100644 --- a/src/app/child-dev-project/aser/model/aser.ts +++ b/src/app/child-dev-project/aser/model/aser.ts @@ -15,87 +15,70 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; -import { WarningLevel } from "../../warning-level"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { mathLevels } from "./mathLevels"; +import { readingLevels } from "./readingLevels"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; @DatabaseEntity("Aser") export class Aser extends Entity { - static ReadingLevels = [ - "Nothing", - "Read Letters", - "Read Words", - "Read Sentence", - "Read Paragraph", - ]; - static MathLevels = [ - "Nothing", - "Numbers 1-9", - "Numbers 10-99", - "Subtraction", - "Division", - ]; - - static isReadingPassedOrNA(level: string) { - if (level === "" || level === undefined) { + static isReadingPassedOrNA(level: ConfigurableEnumValue) { + if (!level || level.id === "") { // not applicable return true; } - return level === this.ReadingLevels[4]; + return level === readingLevels.find((it) => it.id === "read_paragraph"); } - static isMathPassedOrNA(level: string) { - if (level === "" || level === undefined) { + static isMathPassedOrNA(level: ConfigurableEnumValue) { + if (!level || level.id === "") { // not applicable return true; } - return level === this.MathLevels[4]; + return level === mathLevels.find((it) => it.id === "division"); } @DatabaseField() child: string; // id of Child entity - @DatabaseField({ label: "Date", additional: Aser.ReadingLevels }) - date: Date = new Date(); + @DatabaseField({ label: "Date" }) date: Date = new Date(); @DatabaseField({ label: "Hindi", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - hindi: string = ""; + hindi: ConfigurableEnumValue; @DatabaseField({ label: "Bengali", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - bengali: string = ""; + bengali: ConfigurableEnumValue; @DatabaseField({ label: "English", - editComponent: "EditSelectable", - additional: Aser.ReadingLevels, + dataType: "configurable-enum", + innerDataType: "reading-levels", }) - english: string = ""; + english: ConfigurableEnumValue; @DatabaseField({ label: "Math", - editComponent: "EditSelectable", - additional: Aser.MathLevels, + dataType: "configurable-enum", + innerDataType: "math-levels", }) - math: string = ""; + math: ConfigurableEnumValue; @DatabaseField({ label: "Remarks" }) remarks: string = ""; getWarningLevel(): WarningLevel { - let warningLevel; - if ( Aser.isReadingPassedOrNA(this.english) && Aser.isReadingPassedOrNA(this.hindi) && Aser.isReadingPassedOrNA(this.bengali) && Aser.isMathPassedOrNA(this.math) ) { - warningLevel = WarningLevel.OK; + return WarningLevel.OK; } else { - warningLevel = WarningLevel.WARNING; + return WarningLevel.WARNING; } - - return warningLevel; } } diff --git a/src/app/child-dev-project/aser/model/mathLevels.ts b/src/app/child-dev-project/aser/model/mathLevels.ts new file mode 100644 index 0000000000..dda86891a9 --- /dev/null +++ b/src/app/child-dev-project/aser/model/mathLevels.ts @@ -0,0 +1,28 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const mathLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "Nothing", + label: "Nothing", + }, + { + id: "Numbers 1-9", + label: "Numbers 1-9", + }, + { + id: "Numbers 10-99", + label: "Numbers 10-99", + }, + { + id: "Subtraction", + label: "Subtraction", + }, + { + id: "Division", + label: "Division", + }, +]; diff --git a/src/app/child-dev-project/aser/model/readingLevels.ts b/src/app/child-dev-project/aser/model/readingLevels.ts new file mode 100644 index 0000000000..ffc2e7113e --- /dev/null +++ b/src/app/child-dev-project/aser/model/readingLevels.ts @@ -0,0 +1,28 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const readingLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "Nothing", + label: "Nothing", + }, + { + id: "Read Letters", + label: "Read Letters", + }, + { + id: "Read Words", + label: "Read Words", + }, + { + id: "Read Sentence", + label: "Read Sentence", + }, + { + id: "Read Paragraph", + label: "Read Paragraph", + }, +]; diff --git a/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts b/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts index f56801e28f..8d8b739fdc 100644 --- a/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts +++ b/src/app/child-dev-project/attendance/attendance-calendar/attendance-calendar.component.ts @@ -19,7 +19,7 @@ import { } from "../model/calculate-average-event-attendance"; import { EventNote } from "../model/event-note"; import { RecurringActivity } from "../model/recurring-activity"; -import { applyUpdate } from "../../../core/entity/entity-update"; +import { applyUpdate } from "../../../core/entity/model/entity-update"; import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { AttendanceService } from "../attendance.service"; diff --git a/src/app/child-dev-project/attendance/model/activity-attendance.ts b/src/app/child-dev-project/attendance/model/activity-attendance.ts index 2a1cb15c5d..80d70d7b75 100644 --- a/src/app/child-dev-project/attendance/model/activity-attendance.ts +++ b/src/app/child-dev-project/attendance/model/activity-attendance.ts @@ -2,11 +2,11 @@ import { AttendanceLogicalStatus, AttendanceStatusType, } from "./attendance-status"; -import { Entity } from "../../../core/entity/entity"; import { RecurringActivity } from "./recurring-activity"; import { defaultAttendanceStatusTypes } from "../../../core/config/default-config/default-attendance-status-types"; -import { WarningLevel } from "../../warning-level"; import { EventNote } from "./event-note"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; +import { Entity } from "../../../core/entity/model/entity"; /** * Aggregate information about all events for a {@link RecurringActivity} within a given time period. @@ -101,14 +101,14 @@ export class ActivityAttendance extends Entity { return this.countIndividual(childId, AttendanceLogicalStatus.ABSENT); } - getAttendancePercentage(childId: string) { + getAttendancePercentage(childId: string): number { const present = this.countEventsPresent(childId); const absent = this.countEventsAbsent(childId); return present / (present + absent); } - getAttendancePercentageAverage() { + getAttendancePercentageAverage(): number { // TODO calculate overall averaged attendance percentage return NaN; } diff --git a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts index cf2b3298e8..4393506d2f 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.spec.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.spec.ts @@ -16,10 +16,10 @@ */ import { AttendanceMonth, daysInMonth } from "./attendance-month"; -import { WarningLevel } from "../../warning-level"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; describe("AttendanceMonth", () => { const ENTITY_TYPE = "AttendanceMonth"; diff --git a/src/app/child-dev-project/attendance/model/attendance-month.ts b/src/app/child-dev-project/attendance/model/attendance-month.ts index 96a7618e0a..bf0fbe58ff 100644 --- a/src/app/child-dev-project/attendance/model/attendance-month.ts +++ b/src/app/child-dev-project/attendance/model/attendance-month.ts @@ -15,12 +15,12 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; -import { WarningLevel } from "../../warning-level"; +import { Entity } from "../../../core/entity/model/entity"; import { AttendanceDay } from "./attendance-day"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { AttendanceStatus } from "./attendance-status"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * @deprecated Use new system based on EventNote and RecurrentActivity instead @@ -222,7 +222,7 @@ export class AttendanceMonth extends Entity { return this.daysAttended / (this.daysWorking - this.daysExcused); } - getWarningLevel() { + getWarningLevel(): WarningLevel { const attendance = this.getAttendancePercentage(); if (attendance < AttendanceMonth.THRESHOLD_URGENT) { return WarningLevel.URGENT; diff --git a/src/app/child-dev-project/attendance/model/event-note.spec.ts b/src/app/child-dev-project/attendance/model/event-note.spec.ts index 6f7e608a76..24e884216c 100644 --- a/src/app/child-dev-project/attendance/model/event-note.spec.ts +++ b/src/app/child-dev-project/attendance/model/event-note.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EventNote } from "./event-note"; describe("EventNote", () => { diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts b/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts index 6707192b3a..06bb0cbdea 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.spec.ts @@ -18,7 +18,7 @@ import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { RecurringActivity } from "./recurring-activity"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { InteractionType } from "../../notes/model/interaction-type.interface"; import { ConfigurableEnumDatatype } from "../../../core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype"; diff --git a/src/app/child-dev-project/attendance/model/recurring-activity.ts b/src/app/child-dev-project/attendance/model/recurring-activity.ts index 324307ea8a..9006804e80 100644 --- a/src/app/child-dev-project/attendance/model/recurring-activity.ts +++ b/src/app/child-dev-project/attendance/model/recurring-activity.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import { Note } from "../../notes/model/note"; @@ -69,7 +69,7 @@ export class RecurringActivity extends Entity { /** IDs of groups (schools, teams) whose (active) members should be included in the activity*/ @DatabaseField({ - label: "Schools", + label: "Groups", viewComponent: "DisplayEntityArray", editComponent: "EditEntityArray", additional: School.ENTITY_TYPE, @@ -78,7 +78,7 @@ export class RecurringActivity extends Entity { /** IDs of the users who are responsible for conducting this activity */ @DatabaseField({ - label: "Assigned to", + label: "Assigned user(s)", viewComponent: "DisplayEntityArray", editComponent: "EditEntityArray", additional: User.ENTITY_TYPE, diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts index 2fe1b6de5a..a94bcd423a 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.spec.ts @@ -19,7 +19,7 @@ import { TestBed } from "@angular/core/testing"; import { SafeUrl } from "@angular/platform-browser"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ChildPhotoService } from "./child-photo.service"; import { BehaviorSubject } from "rxjs"; import { PhotoDatatype } from "./datatype-photo"; diff --git a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts index 85112757c7..07ada75626 100644 --- a/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts +++ b/src/app/child-dev-project/children/child-photo-service/datatype-photo.ts @@ -19,7 +19,7 @@ import { EntitySchemaDatatype } from "../../../core/entity/schema/entity-schema- import { ChildPhotoService } from "./child-photo.service"; import { EntitySchemaField } from "../../../core/entity/schema/entity-schema-field"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { Photo } from "./photo"; import { SafeUrl } from "@angular/platform-browser"; import { BehaviorSubject } from "rxjs"; diff --git a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts index 80c7b4fc58..651f7931e1 100644 --- a/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts +++ b/src/app/child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component.ts @@ -1,11 +1,11 @@ import { Component, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { HealthCheck } from "../../health-checkup/model/health-check"; -import { WarningLevel } from "../../warning-level"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { take } from "rxjs/operators"; import { ChildrenService } from "../children.service"; import { Child } from "../model/child"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; interface BmiRow { childId: string; @@ -46,7 +46,7 @@ export class ChildrenBmiDashboardComponent .getHealthChecksOfChild(child.getId()) .pipe() .subscribe((results) => { - /** get newest HealtCheck */ + /** get latest HealthCheck */ if (results.length > 0) { this.currentHealthCheck = results.reduce((prev, cur) => cur.date > prev.date ? cur : prev diff --git a/src/app/child-dev-project/children/children.service.spec.ts b/src/app/child-dev-project/children/children.service.spec.ts index 4d3fc57fe6..82410b00c8 100644 --- a/src/app/child-dev-project/children/children.service.spec.ts +++ b/src/app/child-dev-project/children/children.service.spec.ts @@ -3,13 +3,13 @@ import { EntityMapperService } from "../../core/entity/entity-mapper.service"; import { ChildSchoolRelation } from "./model/childSchoolRelation"; import { Child } from "./model/child"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; -import { Gender } from "./model/Gender"; import { School } from "../schools/model/school"; import { TestBed } from "@angular/core/testing"; import moment from "moment"; import { Database } from "../../core/database/database"; import { Note } from "../notes/model/note"; import { PouchDatabase } from "../../core/database/pouch-database"; +import { genders } from "./model/genders"; describe("ChildrenService", () => { let service: ChildrenService; @@ -196,7 +196,7 @@ function generateChildEntities(): Child[] { a1.name = "Arjun A."; a1.projectNumber = "1"; a1.religion = "Hindu"; - a1.gender = Gender.MALE; + a1.gender = genders[1]; a1.dateOfBirth = new Date("2000-03-13"); a1.motherTongue = "Hindi"; a1.center = { id: "delhi", label: "Delhi" }; @@ -206,7 +206,7 @@ function generateChildEntities(): Child[] { a2.name = "Bandana B."; a2.projectNumber = "2"; a2.religion = "Hindu"; - a2.gender = Gender.FEMALE; + a2.gender = genders[2]; a2.dateOfBirth = new Date("2001-01-01"); a2.motherTongue = "Bengali"; a2.center = { id: "kolkata", label: "Kolkata" }; @@ -216,7 +216,7 @@ function generateChildEntities(): Child[] { a3.name = "Chandan C."; a3.projectNumber = "3"; a3.religion = "Hindu"; - a3.gender = Gender.MALE; + a3.gender = genders[1]; a3.dateOfBirth = new Date("2002-07-29"); a3.motherTongue = "Hindi"; a3.center = { id: "kolkata", label: "Kolkata" }; diff --git a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts index 44e2758f96..22b3e30443 100644 --- a/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts +++ b/src/app/child-dev-project/children/demo-data-generators/demo-child-generator.service.ts @@ -1,5 +1,4 @@ import { Child } from "../model/child"; -import { Gender } from "../model/Gender"; import { religions } from "./fixtures/religions"; import { languages } from "./fixtures/languages"; import { dropoutTypes } from "./fixtures/dropout-types"; @@ -8,6 +7,7 @@ import { DemoDataGenerator } from "../../../core/demo-data/demo-data-generator"; import { faker } from "../../../core/demo-data/faker"; import { centersWithProbability } from "./fixtures/centers"; import { addDefaultChildPhoto } from "../../../../../.storybook/utils/addDefaultChildPhoto"; +import { genders } from "../model/genders"; export class DemoChildConfig { count: number; @@ -34,7 +34,7 @@ export class DemoChildGenerator extends DemoDataGenerator { child.name = faker.name.firstName() + " " + faker.name.lastName(); child.projectNumber = id; child.religion = faker.random.arrayElement(religions); - child.gender = faker.random.arrayElement([Gender.MALE, Gender.FEMALE]); + child.gender = faker.random.arrayElement(genders.slice(1)); child.dateOfBirth = faker.dateOfBirth(5, 20); child.motherTongue = faker.random.arrayElement(languages); child.center = faker.random.arrayElement(centersWithProbability); diff --git a/src/app/child-dev-project/children/model/Gender.ts b/src/app/child-dev-project/children/model/Gender.ts deleted file mode 100644 index 9ae34d3661..0000000000 --- a/src/app/child-dev-project/children/model/Gender.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum Gender { - MALE = "M", - FEMALE = "F", -} diff --git a/src/app/child-dev-project/children/model/child.spec.ts b/src/app/child-dev-project/children/model/child.spec.ts index e978042edc..fa4406b894 100644 --- a/src/app/child-dev-project/children/model/child.spec.ts +++ b/src/app/child-dev-project/children/model/child.spec.ts @@ -17,10 +17,10 @@ import { Child } from "./child"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; -import { Gender } from "./Gender"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { PhotoDatatype } from "../child-photo-service/datatype-photo"; +import { genders } from "./genders"; describe("Child", () => { const ENTITY_TYPE = "Child"; @@ -56,7 +56,7 @@ describe("Child", () => { name: "Max", projectNumber: "1", - gender: "M", + gender: genders[1], dateOfBirth: "2010-01-01", motherTongue: "Hindi", religion: "Hindu", @@ -78,7 +78,7 @@ describe("Child", () => { const entity = new Child(id); entity.name = expectedData.name; entity.projectNumber = expectedData.projectNumber; - entity.gender = Gender.MALE; + entity.gender = expectedData.gender; entity.dateOfBirth = new Date(expectedData.dateOfBirth); entity.motherTongue = expectedData.motherTongue; entity.religion = expectedData.religion; diff --git a/src/app/child-dev-project/children/model/child.ts b/src/app/child-dev-project/children/model/child.ts index 2937a3945b..e5e1ef3124 100644 --- a/src/app/child-dev-project/children/model/child.ts +++ b/src/app/child-dev-project/children/model/child.ts @@ -15,8 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; -import { Gender } from "./Gender"; +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/configurable-enum/configurable-enum.interface"; @@ -48,12 +47,11 @@ export class Child extends Entity { dateOfBirth: Date; @DatabaseField({ label: "Mother Tongue" }) motherTongue: string = ""; @DatabaseField({ - dataType: "string", + dataType: "configurable-enum", label: "Gender", - additional: ["", "M", "F"], - editComponent: "EditSelectable", + innerDataType: "genders", }) - gender: Gender; // M or F + gender: ConfigurableEnumValue; @DatabaseField({ label: "Religion" }) religion: string = ""; @DatabaseField({ diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts index 5ff9a90cf9..3ae8fe484d 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.spec.ts @@ -17,10 +17,9 @@ import { waitForAsync } from "@angular/core/testing"; import { ChildSchoolRelation } from "./childSchoolRelation"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import moment from "moment"; -import { FormBuilder } from "@angular/forms"; describe("ChildSchoolRelation Entity", () => { const ENTITY_TYPE = "ChildSchoolRelation"; @@ -100,37 +99,26 @@ describe("ChildSchoolRelation Entity", () => { expect(relation.isActive).toBeTrue(); }); - it("should fail validation when no school is defined", () => { - const formGroup = new FormBuilder().group({ schoolId: null }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); - }); - it("should fail validation when end date but no start date is defined", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - end: new Date(), - start: null, - }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.end = new Date(); + expect(() => relation.assertValid()).toThrowError(); }); it("should fail validation when start date is after end date", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - start: moment().add(1, "day"), - end: new Date(), - }); - expect(() => ChildSchoolRelation.validateForm(formGroup)).toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.start = moment().add(1, "day").toDate(); + relation.end = new Date(); + expect(() => relation.assertValid()).toThrowError(); }); it("does pass validation when the start date is before the end date", () => { - const formGroup = new FormBuilder().group({ - schoolId: "someId", - start: moment().subtract(1, "day"), - end: new Date(), - }); - expect(() => - ChildSchoolRelation.validateForm(formGroup) - ).not.toThrowError(); + const relation = new ChildSchoolRelation(); + relation.schoolId = "someId"; + relation.start = moment().subtract(1, "day").toDate(); + relation.end = new Date(); + expect(() => relation.assertValid()).not.toThrowError(); }); }); diff --git a/src/app/child-dev-project/children/model/childSchoolRelation.ts b/src/app/child-dev-project/children/model/childSchoolRelation.ts index 53262b0ebf..cc18b48539 100644 --- a/src/app/child-dev-project/children/model/childSchoolRelation.ts +++ b/src/app/child-dev-project/children/model/childSchoolRelation.ts @@ -1,41 +1,21 @@ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; import moment from "moment"; import { School } from "../../schools/model/school"; -import { FormGroup } from "@angular/forms"; /** * Record of a school year that a Child attended a certain class in a School. */ @DatabaseEntity("ChildSchoolRelation") export class ChildSchoolRelation extends Entity { - static validateForm(formGroup: FormGroup) { - super.validateForm(formGroup); - const school = formGroup.get("schoolId")?.value; - const schoolLabel = ChildSchoolRelation.schema.get("schoolId").label; - const startDate: Date = formGroup.get("start")?.value; - const startLabel = ChildSchoolRelation.schema.get("start").label; - const endDate: Date = formGroup.get("end")?.value; - const endLabel = ChildSchoolRelation.schema.get("end").label; - if (!school) { - throw new Error(`No "${schoolLabel}" selected`); - } - if (endDate && !startDate) { - throw new Error(`No "${startLabel}" date is set`); - } else if (moment(startDate).isAfter(endDate, "days")) { - throw new Error( - `The "${startLabel}" date is after the "${endLabel}" date` - ); - } - } - @DatabaseField() childId: string; @DatabaseField({ label: "School", viewComponent: "DisplayEntity", editComponent: "EditSingleEntity", additional: School.ENTITY_TYPE, + required: true, }) schoolId: string; @DatabaseField({ label: "Class" }) schoolClass: string = ""; @@ -57,4 +37,17 @@ export class ChildSchoolRelation extends Entity { (!this.end || moment(this.end).isAfter(moment(), "day")) ); } + + assertValid() { + super.assertValid(); + const startLabel = this.getSchema().get("start").label; + const endLabel = this.getSchema().get("end").label; + if (this.end && !this.start) { + throw new Error(`No "${startLabel}" date is set`); + } else if (moment(this.start).isAfter(this.end, "days")) { + throw new Error( + `The "${startLabel}" date is after the "${endLabel}" date` + ); + } + } } diff --git a/src/app/child-dev-project/children/model/genders.ts b/src/app/child-dev-project/children/model/genders.ts new file mode 100644 index 0000000000..d7ee51416f --- /dev/null +++ b/src/app/child-dev-project/children/model/genders.ts @@ -0,0 +1,16 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const genders: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "M", + label: "male", + }, + { + id: "F", + label: "female", + }, +]; diff --git a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts index 24d508c162..401f91cca8 100644 --- a/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts +++ b/src/app/child-dev-project/educational-material/demo-educational-material-generator.service.ts @@ -4,6 +4,7 @@ import { Injectable } from "@angular/core"; import { Child } from "../children/model/child"; import { faker } from "../../core/demo-data/faker"; import { EducationalMaterial } from "./model/educational-material"; +import { materials } from "./model/materials"; export class DemoEducationMaterialConfig { minCount: number; @@ -51,7 +52,7 @@ export class DemoEducationalMaterialGeneratorService extends DemoDataGenerator material.hasOwnProperty("color")) ); specialMaterial.materialAmount = 1; data.push(specialMaterial); @@ -69,9 +70,7 @@ export class DemoEducationalMaterialGeneratorService extends DemoDataGenerator -
Total: {{ getSummary() }}
+
Total: {{ summary }}
diff --git a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts index 5120ba8a67..e2e838d509 100644 --- a/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts +++ b/src/app/child-dev-project/educational-material/educational-material-component/educational-material.component.ts @@ -16,8 +16,7 @@ export class EducationalMaterialComponent implements OnChanges, OnInitDynamicComponent { @Input() child: Child; records = new Array(); - - materialTypes = EducationalMaterial.MATERIAL_ALL; + summary = ""; columns: FormFieldConfig[] = [ { id: "date", visibleFrom: "xs" }, @@ -52,41 +51,35 @@ export class EducationalMaterialComponent (a, b) => (b.date ? b.date.valueOf() : 0) - (a.date ? a.date.valueOf() : 0) ); + this.updateSummary(); }); } generateNewRecordFactory() { - // define values locally because "this" is a different scope after passing a function as input to another component - const child = this.child.getId(); - return () => { const newAtt = new EducationalMaterial(Date.now().toString()); // use last entered date as default, otherwise today's date newAtt.date = this.records.length > 0 ? this.records[0].date : new Date(); - newAtt.child = child; + newAtt.child = this.child.getId(); return newAtt; }; } - getSummary() { - if (this.records.length === 0) { - return ""; - } - + updateSummary() { const summary = new Map(); this.records.forEach((m) => { - const previousValue = summary.has(m.materialType) - ? summary.get(m.materialType) + const previousValue = summary.has(m.materialType.label) + ? summary.get(m.materialType.label) : 0; - summary.set(m.materialType, previousValue + m.materialAmount); + summary.set(m.materialType.label, previousValue + m.materialAmount); }); let summaryText = ""; summary.forEach( (v, k) => (summaryText = summaryText + k + ": " + v + ", ") ); - return summaryText; + this.summary = summaryText; } } diff --git a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts index 142373fcca..00a08a98eb 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.spec.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.spec.ts @@ -17,8 +17,9 @@ import { waitForAsync } from "@angular/core/testing"; import { EducationalMaterial } from "./educational-material"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; +import { materials } from "./materials"; describe("EducationalMaterial Entity", () => { const ENTITY_TYPE = "EducationalMaterial"; @@ -54,7 +55,7 @@ describe("EducationalMaterial Entity", () => { child: "1", date: new Date(), - materialType: "foo", + materialType: materials[1], materialAmount: 2, description: "bar", diff --git a/src/app/child-dev-project/educational-material/model/educational-material.ts b/src/app/child-dev-project/educational-material/model/educational-material.ts index 4e311c6082..c22274bcd8 100644 --- a/src/app/child-dev-project/educational-material/model/educational-material.ts +++ b/src/app/child-dev-project/educational-material/model/educational-material.ts @@ -15,66 +15,25 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +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/configurable-enum/configurable-enum.interface"; @DatabaseEntity("EducationalMaterial") export class EducationalMaterial extends Entity { - static MATERIAL_STATIONARIES = [ - "pencil", - "eraser", - "sharpener", - "pen (black)", - "pen (blue)", - "oil pastels", - "crayons", - "sketch pens", - "scale (big)", - "scale (small)", - "geometry box", - "copy (single line, small)", - "copy (single line, big)", - "copy (four line)", - "copy (squared)", - "copy (plain)", - "copy (line-plain)", - "copy (drawing)", - "copy (practical)", - "graph book", - "project papers", - "project file", - "scrap book", - "exam board", - ]; - static MATERIAL_OTHER = [ - "Bag", - "School Uniform", - "School Shoes", - "Sports Dress", - "Sports Shoes", - "Raincoat", - ]; - static MATERIAL_ALL = EducationalMaterial.MATERIAL_STATIONARIES.concat( - EducationalMaterial.MATERIAL_OTHER - ); - @DatabaseField() child: string; // id of Child entity @DatabaseField({ label: "Date" }) date: Date; @DatabaseField({ label: "Material", - editComponent: "EditSelectable", - additional: EducationalMaterial.MATERIAL_ALL, + dataType: "configurable-enum", + innerDataType: "materials", }) - materialType = ""; + materialType: ConfigurableEnumValue; @DatabaseField({ label: "Amount" }) materialAmount: number; @DatabaseField({ label: "Description" }) description = ""; public getColor() { - if (EducationalMaterial.MATERIAL_STATIONARIES.includes(this.materialType)) { - return "white"; - } else { - return "#B3E5FC"; - } + return this.materialType?.color || "white"; } } diff --git a/src/app/child-dev-project/educational-material/model/materials.ts b/src/app/child-dev-project/educational-material/model/materials.ts new file mode 100644 index 0000000000..924559ac93 --- /dev/null +++ b/src/app/child-dev-project/educational-material/model/materials.ts @@ -0,0 +1,126 @@ +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; + +export const materials: ConfigurableEnumValue[] = [ + { + id: "pencil", + label: "pencil", + }, + { + id: "eraser", + label: "eraser", + }, + { + id: "sharpener", + label: "sharpener", + }, + { + id: "pen (black)", + label: "pen (black)", + }, + { + id: "oil pastels", + label: "oil pastels", + }, + { + id: "crayons", + label: "crayons", + }, + { + id: "sketch pens", + label: "sketch pens", + }, + { + id: "scale (big)", + label: "scale (big)", + }, + { + id: "scale (small)", + label: "scale (small)", + }, + { + id: "geometry box", + label: "geometry box", + }, + { + id: "copy (single line, small)", + label: "copy (single line, small)", + }, + { + id: "copy (single line, big)", + label: "copy (single line, big)", + }, + { + id: "copy (four line)", + label: "copy (four line)", + }, + { + id: "copy (squared)", + label: "copy (squared)", + }, + { + id: "copy (plain)", + label: "copy (plain)", + }, + { + id: "copy (line-plain)", + label: "copy (line-plain)", + }, + { + id: "copy (drawing)", + label: "copy (drawing)", + }, + { + id: "copy (practical)", + label: "copy (practical)", + }, + { + id: "graph book", + label: "graph book", + }, + { + id: "project papers", + label: "project papers", + }, + { + id: "project file", + label: "project file", + }, + { + id: "scrap book", + label: "scrap book", + }, + { + id: "exam board", + label: "exam board", + }, + { + id: "Bag", + label: "Bag", + color: "#B3E5FC", + }, + { + id: "School Uniform", + label: "School Uniform", + color: "#B3E5FC", + }, + { + id: "School Shoes", + label: "School Shoes", + color: "#B3E5FC", + }, + { + id: "Sports Dress", + label: "Sports Dress", + color: "#B3E5FC", + }, + { + id: "Sports Shoes", + label: "Sports Shoes", + color: "#B3E5FC", + }, + { + id: "Raincoat", + label: "Raincoat", + color: "#B3E5FC", + }, +]; diff --git a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts index 89a2ee2c44..63fdf0566d 100644 --- a/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts +++ b/src/app/child-dev-project/health-checkup/health-checkup-component/health-checkup.stories.ts @@ -30,7 +30,10 @@ export default { imports: [ChildrenModule], declarations: [], providers: [ - { provide: EntityMapperService, useValue: {} }, + { + provide: EntityMapperService, + useValue: { save: () => Promise.resolve() }, + }, { provide: ChildrenService, useValue: { getHealthChecksOfChild: () => of([hc1, hc2, hc3]) }, diff --git a/src/app/child-dev-project/health-checkup/model/health-check.spec.ts b/src/app/child-dev-project/health-checkup/model/health-check.spec.ts index 1b165fbaad..c9d4ed5d09 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.spec.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.spec.ts @@ -16,7 +16,7 @@ */ import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HealthCheck } from "./health-check"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; diff --git a/src/app/child-dev-project/health-checkup/model/health-check.ts b/src/app/child-dev-project/health-checkup/model/health-check.ts index 04ab7bbb6f..1e471eb2f6 100644 --- a/src/app/child-dev-project/health-checkup/model/health-check.ts +++ b/src/app/child-dev-project/health-checkup/model/health-check.ts @@ -15,10 +15,10 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { WarningLevel } from "../../warning-level"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * Model Class for the Health Checks that are taken for a Child. @@ -49,7 +49,7 @@ export class HealthCheck extends Entity { return this.weight / ((this.height / 100) * (this.height / 100)); } - getWarningLevel() { + getWarningLevel(): WarningLevel { if (this.bmi <= 16 || this.bmi >= 30) { return WarningLevel.URGENT; } else if (this.bmi >= 18 && this.bmi <= 25) { diff --git a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts index da6e309b8e..d6bc4f1412 100644 --- a/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts +++ b/src/app/child-dev-project/notes/demo-data/demo-note-generator.service.ts @@ -4,7 +4,7 @@ import { Injectable } from "@angular/core"; import { Child } from "../../children/model/child"; import { Note } from "../model/note"; import { faker } from "../../../core/demo-data/faker"; -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; import { noteIndividualStories } from "./notes_individual-stories"; import { noteGroupStories } from "./notes_group-stories"; import { centersUnique } from "../../children/demo-data-generators/fixtures/centers"; @@ -146,7 +146,7 @@ export class DemoNoteGeneratorService extends DemoDataGenerator { const lastMonths = new Date(); lastMonths.setMonth(lastMonths.getMonth() - 1); if (note.date < lastMonths) { - note.warningLevel = WarningLevel.OK; + note.warningLevel = warningLevels.find((level) => level.id === "OK"); } } diff --git a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts index df640c61e3..34b231daeb 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_group-stories.ts @@ -1,16 +1,16 @@ -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; export const noteGroupStories = [ { category: "GUARDIAN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Guardians Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "GUARDIAN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Guardians Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", @@ -18,21 +18,21 @@ export const noteGroupStories = [ { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Children Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Children Meeting", text: "Our regular monthly meeting. Find the agenda and minutes in our meeting folder.", }, { category: "CHILDREN_MEETING", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Drug Prevention Workshop", text: "Expert conducted a two day workshop on drug prevention.", }, diff --git a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts index 3914ba9849..a630c3cf5c 100644 --- a/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts +++ b/src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts @@ -1,9 +1,9 @@ -import { WarningLevel } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; export const noteIndividualStories = [ { category: "HOME_VISIT", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Mother sick", text: "Visited family after we heard that mother is seriously ill. She cannot get up. " + @@ -12,7 +12,7 @@ export const noteIndividualStories = [ }, { category: "GUARDIAN_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Discussed school change", text: "Discussed future of the child with the parents. They agree that changing school can be a good option. " + @@ -21,21 +21,21 @@ export const noteIndividualStories = [ { category: "PHONE_CALL", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Follow up for school absence", text: "Called to ask for reason about absence. Mother made excuses but promised to send the child tomorrow.", }, { category: "PHONE_CALL", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Absent because ill", text: "Mother has called in the morning. Child cannot come to class because of fever.", }, { category: "PHONE_CALL", - warningLevel: WarningLevel.URGENT, + warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: "Absence without information", text: "Child was not in school whole last week again. When calling the mother she didn't know about it. " + @@ -44,7 +44,7 @@ export const noteIndividualStories = [ { category: "VISIT", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "School is happy about progress", text: "Visited the school and talked to the class teacher and principal. They are happy about the progress " + @@ -52,7 +52,7 @@ export const noteIndividualStories = [ }, { category: "COACHING_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Needs to work more for school", text: "Discussed the child's progress with coaching teacher. He is still a weak student and needs more support. " + @@ -61,7 +61,7 @@ export const noteIndividualStories = [ { category: "INCIDENT", - warningLevel: WarningLevel.URGENT, + warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: "Fight at school", text: "Principal called us today. Our student got into a fight and was suspended for a week. " + @@ -70,7 +70,7 @@ export const noteIndividualStories = [ { category: "DISCUSSION", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Special help for family", text: "Since the father has lost his job the family is struggling to survive. " + @@ -78,7 +78,7 @@ export const noteIndividualStories = [ }, { category: "DISCUSSION", - warningLevel: WarningLevel.OK, + warningLevel: warningLevels.find((level) => level.id === "OK"), subject: "Chance to repeat class", text: "Child has failed this school year as she did not go to school regularly. " + @@ -88,7 +88,7 @@ export const noteIndividualStories = [ { category: "CHILD_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Distracted in class", text: "Teacher has let us know that he is very unfocused during class these days. " + @@ -96,7 +96,7 @@ export const noteIndividualStories = [ }, { category: "CHILD_TALK", - warningLevel: WarningLevel.WARNING, + warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: "Disturbing class", text: "She refused to listen to the teacher was disturbing the class. " + diff --git a/src/app/child-dev-project/notes/model/note.spec.ts b/src/app/child-dev-project/notes/model/note.spec.ts index 4a5b283a0f..4d583ac9ea 100644 --- a/src/app/child-dev-project/notes/model/note.spec.ts +++ b/src/app/child-dev-project/notes/model/note.spec.ts @@ -1,8 +1,8 @@ import { Note } from "./note"; -import { WarningLevel, WarningLevelColor } from "../../warning-level"; +import { warningLevels } from "../../warning-levels"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ATTENDANCE_STATUS_CONFIG_ID, AttendanceLogicalStatus, @@ -19,6 +19,10 @@ import { ConfigurableEnumConfig, } from "../../../core/configurable-enum/configurable-enum.interface"; import { createTestingConfigService } from "../../../core/config/config.service"; +import { + getWarningLevelColor, + WarningLevel, +} from "../../../core/entity/model/warning-level"; const testStatusTypes: ConfigurableEnumConfig = [ { @@ -47,7 +51,7 @@ function createTestModel(): Note { n1.subject = "Note Subject"; n1.text = "Note text"; n1.authors = ["1"]; - n1.warningLevel = WarningLevel.URGENT; + n1.warningLevel = warningLevels.find((level) => level.id === "URGENT"); return n1; } @@ -110,7 +114,7 @@ describe("Note", () => { text: "Note text", authors: ["1"], category: "GUARDIAN_TALK", - warningLevel: WarningLevel.URGENT, + warningLevel: "OK", searchIndices: [], }; @@ -120,6 +124,7 @@ describe("Note", () => { entity.category = testInteractionTypes.find( (c) => c.id === "GUARDIAN_TALK" ); + entity.warningLevel = warningLevels.find((level) => level.id === "OK"); const rawData = entitySchemaService.transformEntityToDatabaseFormat(entity); @@ -157,10 +162,12 @@ describe("Note", () => { it("should return colors", function () { const note = new Note("1"); + note.category = { id: "", label: "test", color: "#FFFFFF" }; expect(note.getColor()).toBe("#FFFFFF"); - note.warningLevel = WarningLevel.URGENT; - expect(note.getColor()).toBe(WarningLevelColor(WarningLevel.URGENT)); + + note.warningLevel = warningLevels.find((level) => level.id === "URGENT"); + expect(note.getColor()).toBe(getWarningLevelColor(WarningLevel.URGENT)); }); it("transforms interactionType from config", function () { diff --git a/src/app/child-dev-project/notes/model/note.ts b/src/app/child-dev-project/notes/model/note.ts index a345ae6aa8..66d70425ac 100644 --- a/src/app/child-dev-project/notes/model/note.ts +++ b/src/app/child-dev-project/notes/model/note.ts @@ -16,9 +16,8 @@ */ import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; -import { WarningLevel, WarningLevelColor } from "../../warning-level"; import { INTERACTION_TYPE_CONFIG_ID, InteractionType, @@ -30,6 +29,11 @@ import { } from "../../attendance/model/attendance-status"; import { User } from "../../../core/user/user"; import { Child } from "../../children/model/child"; +import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; +import { + getWarningLevelColor, + WarningLevel, +} from "../../../core/entity/model/warning-level"; @DatabaseEntity("Note") export class Note extends Entity { @@ -95,38 +99,37 @@ export class Note extends Entity { @DatabaseField() schools: string[] = []; @DatabaseField({ - dataType: "string", label: "", - editComponent: "EditSelectable", - additional: ["OK", "WARNING", "URGENT"], + dataType: "configurable-enum", + innerDataType: "warning-levels", }) - warningLevel: WarningLevel = WarningLevel.OK; + warningLevel: ConfigurableEnumValue; getWarningLevel(): WarningLevel { - return this.warningLevel; + if (this.warningLevel) { + return WarningLevel[this.warningLevel.id]; + } else { + return WarningLevel.NONE; + } } - // TODO: color logic should not be part of entity/model but rather in the component responsible for displaying it public getColor() { - if (this.warningLevel === WarningLevel.URGENT) { - return WarningLevelColor(WarningLevel.URGENT); - } - if (this.warningLevel === WarningLevel.WARNING) { - return WarningLevelColor(WarningLevel.WARNING); + const actualLevel = this.getWarningLevel(); + if (actualLevel === WarningLevel.OK || actualLevel === WarningLevel.NONE) { + return this.category.color; + } else { + return super.getColor(); } - - const color = this.category.color; - return color ? color : ""; } - public getColorForId(childId: string) { + public getColorForId(childId: string): string { if ( this.category.isMeeting && this.childrenAttendance.get(childId)?.status.countAs === AttendanceLogicalStatus.ABSENT ) { // child is absent, highlight the entry - return WarningLevelColor(WarningLevel.URGENT); + return getWarningLevelColor(WarningLevel.URGENT); } return this.getColor(); } diff --git a/src/app/child-dev-project/notes/note-details/note-details.component.html b/src/app/child-dev-project/notes/note-details/note-details.component.html index 2f9d2839f2..799ea46d80 100644 --- a/src/app/child-dev-project/notes/note-details/note-details.component.html +++ b/src/app/child-dev-project/notes/note-details/note-details.component.html @@ -47,9 +47,12 @@

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}

Status - Solved - Needs Follow-Up - Urgent Follow-Up + + {{ warningLevel.label }} +
@@ -76,7 +79,7 @@

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}

{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}
{{ entity.date?.toLocaleDateString() }}: {{ entity.subject }}
{ let component: NotesManagerComponent; diff --git a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts index 4490f9ef61..9ce04fc31f 100644 --- a/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts +++ b/src/app/child-dev-project/notes/notes-manager/notes-manager.component.ts @@ -1,9 +1,8 @@ -import { Component, OnInit, ViewChild } from "@angular/core"; +import { Component, Input, OnInit, ViewChild } from "@angular/core"; import { Note } from "../model/note"; import { MediaObserver } from "@angular/flex-layout"; import { NoteDetailsComponent } from "../note-details/note-details.component"; import { ActivatedRoute } from "@angular/router"; -import { WarningLevel } from "../../warning-level"; import { EntityMapperService } from "../../../core/entity/entity-mapper.service"; import { FilterSelectionOption } from "../../../core/filter/filter-selection/filter-selection"; import { SessionService } from "../../../core/session/session-service/session.service"; @@ -11,11 +10,11 @@ import { FormDialogService } from "../../../core/form-dialog/form-dialog.service import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { LoggingService } from "../../../core/logging/logging.service"; import { EntityListComponent } from "../../../core/entity-components/entity-list/entity-list.component"; -import { applyUpdate } from "../../../core/entity/entity-update"; +import { applyUpdate } from "../../../core/entity/model/entity-update"; import { EntityListConfig } from "../../../core/entity-components/entity-list/EntityListConfig"; -import { Input } from "@angular/core"; import { EventNote } from "../../attendance/model/event-note"; -import { EntityConstructor } from "../../../core/entity/entity"; +import { EntityConstructor } from "../../../core/entity/model/entity"; +import { WarningLevel } from "../../../core/entity/model/warning-level"; /** * additional config specifically for NotesManagerComponent @@ -48,14 +47,14 @@ export class NotesManagerComponent implements OnInit { { key: "urgent", label: "Urgent", - filterFun: (n: Note) => n.warningLevel === WarningLevel.URGENT, + filterFun: (n: Note) => n.getWarningLevel() === WarningLevel.URGENT, }, { key: "follow-up", label: "Needs Follow-Up", filterFun: (n: Note) => - n.warningLevel === WarningLevel.WARNING || - n.warningLevel === WarningLevel.URGENT, + n.getWarningLevel() === WarningLevel.URGENT || + n.getWarningLevel() === WarningLevel.WARNING, }, { key: "", label: "All", filterFun: () => true }, ]; diff --git a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts index bd6d541bd1..c3c178c179 100644 --- a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts +++ b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.spec.ts @@ -16,7 +16,7 @@ */ import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { ProgressDashboardConfig } from "./progress-dashboard-config"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; diff --git a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts index 66b7fa8189..56de0330ee 100644 --- a/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts +++ b/src/app/child-dev-project/progress-dashboard-widget/progress-dashboard/progress-dashboard-config.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; diff --git a/src/app/child-dev-project/schools/model/school.spec.ts b/src/app/child-dev-project/schools/model/school.spec.ts index 461498fafe..f8c8ee235d 100644 --- a/src/app/child-dev-project/schools/model/school.spec.ts +++ b/src/app/child-dev-project/schools/model/school.spec.ts @@ -17,7 +17,7 @@ import { waitForAsync } from "@angular/core/testing"; import { School } from "./school"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { EntitySchemaService } from "../../../core/entity/schema/entity-schema.service"; describe("School Entity", () => { diff --git a/src/app/child-dev-project/schools/model/school.ts b/src/app/child-dev-project/schools/model/school.ts index 70a9d7a4d8..a96cd8244e 100644 --- a/src/app/child-dev-project/schools/model/school.ts +++ b/src/app/child-dev-project/schools/model/school.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { DatabaseEntity } from "../../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../../core/entity/database-field.decorator"; @@ -13,12 +13,7 @@ export class School extends Entity { @DatabaseField({ label: "Medium" }) medium: string = ""; @DatabaseField({ label: "Remarks" }) remarks: string = ""; @DatabaseField({ label: "Website" }) website: string = ""; - @DatabaseField({ - label: "Private School", - editComponent: "EditBoolean", - viewComponent: "DisplayCheckmark", - }) - privateSchool: boolean; + @DatabaseField({ label: "Private School" }) privateSchool: boolean; @DatabaseField({ label: "Contact Number" }) phone: string = ""; @DatabaseField({ label: "Teaching up to class" }) upToClass: number; @DatabaseField({ label: "Board" }) academicBoard: string = ""; diff --git a/src/app/child-dev-project/warning-levels.ts b/src/app/child-dev-project/warning-levels.ts new file mode 100644 index 0000000000..3c93235ee4 --- /dev/null +++ b/src/app/child-dev-project/warning-levels.ts @@ -0,0 +1,20 @@ +import { ConfigurableEnumValue } from "../core/configurable-enum/configurable-enum.interface"; + +export const warningLevels: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "OK", + label: "Solved", + }, + { + id: "WARNING", + label: "Needs Follow-Up", + }, + { + id: "URGENT", + label: "Urgent Follow-Up", + }, +]; diff --git a/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts b/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts index cdc17397a5..25321199b8 100644 --- a/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts +++ b/src/app/conflict-resolution/conflict-resolution-list/conflict-resolution-list.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, Component, Optional, ViewChild } from "@angular/core"; import { MatPaginator } from "@angular/material/paginator"; import { QueryDataSource } from "../../core/database/query-data-source"; -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { Database } from "../../core/database/database"; import { EntitySchemaService } from "../../core/entity/schema/entity-schema.service"; diff --git a/src/app/core/admin/admin/admin.component.html b/src/app/core/admin/admin/admin.component.html index 9b7fb897a2..e9544dadee 100644 --- a/src/app/core/admin/admin/admin.component.html +++ b/src/app/core/admin/admin/admin.component.html @@ -21,7 +21,7 @@

Utility Functions

-

diff --git a/src/app/core/admin/admin/admin.component.ts b/src/app/core/admin/admin/admin.component.ts index aa1fb18b14..b458f5d425 100644 --- a/src/app/core/admin/admin/admin.component.ts +++ b/src/app/core/admin/admin/admin.component.ts @@ -58,6 +58,10 @@ export class AdminComponent implements OnInit { this.childPhotoUpdateService.updateChildrenPhotoFilenames(); } + async migrateConfigChanges() { + await this.configMigrationService.migrateConfig(); + } + /** * Send a reference of the PouchDB to the browser's developer console for real-time debugging. */ diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 06d05b0413..82d3ca7632 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -1,10 +1,14 @@ import { defaultAttendanceStatusTypes } from "./default-config/default-attendance-status-types"; import { defaultInteractionTypes } from "./default-config/default-interaction-types"; import { Child } from "../../child-dev-project/children/model/child"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; import { EventNote } from "../../child-dev-project/attendance/model/event-note"; +import { genders } from "../../child-dev-project/children/model/genders"; +import { materials } from "../../child-dev-project/educational-material/model/materials"; +import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; +import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; +import { warningLevels } from "../../child-dev-project/warning-levels"; import { ratingAnswers } from "../../features/historical-data/rating-answers"; // prettier-ignore @@ -76,9 +80,12 @@ export const defaultJsonConfig = { "enum:interaction-type": defaultInteractionTypes, - "enum:attendance-status": defaultAttendanceStatusTypes, - + "enum:reading-levels": readingLevels, + "enum:math-levels": mathLevels, + "enum:genders": genders, + "enum:materials": materials, + "enum:warning-levels": warningLevels, "enum:document-status": [ { "id": "", @@ -702,8 +709,8 @@ export const defaultJsonConfig = { "query": `${Child.ENTITY_TYPE}:toArray[*isActive=true]`, "label": "All children", "aggregations": [ - {"label": "Male children", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, { @@ -716,8 +723,8 @@ export const defaultJsonConfig = { "query": `[*privateSchool!=true]:getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId)[*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique:toEntities`, "label": "Children attending a governmental school", "aggregations": [ - {"label": "Male children attending a governmental school", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children attending a governmental school", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children attending a governmental school", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children attending a governmental school", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, {"label": "Private schools", "query": `[*privateSchool=true]`}, @@ -725,8 +732,8 @@ export const defaultJsonConfig = { "query": `[*privateSchool=true]:getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId)[*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique:toEntities`, "label": "Children attending a private school", "aggregations": [ - {"label": "Male children attending a private school", "query": `[*gender=${Gender.MALE}]`}, - {"label": "Female children attending a private school", "query": `[*gender=${Gender.FEMALE}]`}, + {"label": "Male children attending a private school", "query": `:filterByObjectAttribute(gender, id, M)`}, + {"label": "Female children attending a private school", "query": `:filterByObjectAttribute(gender, id, F)`}, ] }, ] diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 3b90bf760b..08623156e4 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -5,6 +5,12 @@ import { ConfigService } from "./config.service"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { Config } from "./config"; import { EntityConfig } from "../entity/entity-config.service"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumValue, +} from "../configurable-enum/configurable-enum.interface"; +import { genders } from "../../child-dev-project/children/model/genders"; +import { EntitySchemaField } from "../entity/schema/entity-schema-field"; describe("ConfigMigrationService", () => { let service: ConfigMigrationService; @@ -154,6 +160,12 @@ describe("ConfigMigrationService", () => { placeholder: "Gender", options: ["M", "F"], }, + { + input: "select", + id: "status", + placeholder: "Status", + options: ["Active", "Inactive", "Still Considering"], + }, ], [ { @@ -292,13 +304,35 @@ describe("ConfigMigrationService", () => { const childConfig = configService.getConfig("entity:Child"); const centerSchema = childConfig.attributes.find( (attr) => attr.name === "center" - ); - expect(centerSchema.schema).toEqual(expectedCenterSchema); + ).schema; + expect(centerSchema).toEqual(expectedCenterSchema); }); it("should migrate the details configs", async () => { const childDetailsConfig = configService.getConfig("view:child/:id"); expect(childDetailsConfig).toEqual(expectedChildDetailsConfig); + + const childConfig = configService.getConfig("entity:Child"); + const genderSchema = childConfig.attributes.find( + (attr) => attr.name === "gender" + ).schema; + expect(genderSchema).toEqual(expectedGenderSchema); + + const statusSchema = childConfig.attributes.find( + (attr) => attr.name === "status" + ).schema; + expect(statusSchema).toEqual(expectedStatusSchema); + const statusEnum = configService.getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + "status" + ); + expect(statusEnum).toEqual(expectedStatusConfigurableEnum); + }); + + it("should add configurable enum configs", () => { + const genderConfig = configService.getConfig( + CONFIGURABLE_ENUM_CONFIG_PREFIX + "genders" + ); + expect(genderConfig).toEqual(genders); }); }); const expectedChildrenListConfig = { @@ -389,13 +423,46 @@ const expectedChildrenListConfig = { }, }; -const expectedCenterSchema = { +const expectedCenterSchema: EntitySchemaField = { dataType: "configurable-enum", innerDataType: "center", labelShort: "Center", label: "Center", }; +const expectedGenderSchema: EntitySchemaField = { + dataType: "configurable-enum", + innerDataType: "genders", + label: "Gender", + labelShort: "Gender", +}; + +const expectedStatusSchema: EntitySchemaField = { + dataType: "configurable-enum", + innerDataType: "status", + label: "Status", + labelShort: "Status", +}; + +const expectedStatusConfigurableEnum: ConfigurableEnumValue[] = [ + { + id: "", + label: "", + }, + { + id: "Active", + label: "Active", + }, + { + id: "Inactive", + label: "Inactive", + }, + { + id: "Still Considering", + label: "Still Considering", + }, +]; + const expectedChildDetailsConfig = { component: "EntityDetails", _id: "view:child/:id", @@ -441,10 +508,12 @@ const expectedChildDetailsConfig = { label: "Date of Birth", }, { - edit: "EditSelectable", id: "gender", label: "Gender", - additional: ["M", "F"], + }, + { + id: "status", + label: "Status", }, ], [ diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 082dc08f63..0139f26f13 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -10,7 +10,7 @@ import { } from "../entity-components/entity-list/EntityListConfig"; import { FormFieldConfig } from "../entity-components/entity-form/entity-form/FormConfig"; import { ENTITY_MAP } from "../entity-components/entity-details/entity-details.component"; -import { Entity, EntityConstructor } from "../entity/entity"; +import { Entity, EntityConstructor } from "../entity/model/entity"; import { EntityConfig, EntityConfigService, @@ -23,6 +23,15 @@ import { ChildSchoolRelation } from "../../child-dev-project/children/model/chil import { HistoricalEntityData } from "../../features/historical-data/historical-entity-data"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; import { HealthCheck } from "../../child-dev-project/health-checkup/model/health-check"; +import { readingLevels } from "../../child-dev-project/aser/model/readingLevels"; +import { mathLevels } from "../../child-dev-project/aser/model/mathLevels"; +import { genders } from "../../child-dev-project/children/model/genders"; +import { materials } from "../../child-dev-project/educational-material/model/materials"; +import { + CONFIGURABLE_ENUM_CONFIG_PREFIX, + ConfigurableEnumValue, +} from "../configurable-enum/configurable-enum.interface"; +import { warningLevels } from "../../child-dev-project/warning-levels"; @Injectable({ providedIn: "root", @@ -43,6 +52,27 @@ export class ConfigMigrationService { async migrateConfig(): Promise { this.config = await this.configService.loadConfig(this.entityMapper); + this.addNewConfigurableEnums(); + this.migrateViewConfigs(); + console.log("config", this.config); + return this.configService.saveConfig(this.entityMapper, this.config.data); + } + + private addNewConfigurableEnums() { + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "reading-levels" + ] = readingLevels; + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "math-levels" + ] = mathLevels; + this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "genders"] = genders; + this.config.data[CONFIGURABLE_ENUM_CONFIG_PREFIX + "materials"] = materials; + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + "warning-levels" + ] = warningLevels; + } + + private migrateViewConfigs() { const viewConfigs = this.configService.getAllConfigs("view:"); viewConfigs.forEach((viewConfig) => { const entity = this.getEntity(viewConfig._id); @@ -53,8 +83,6 @@ export class ConfigMigrationService { this.migrateEntityDetailsConfig(viewConfig.config, entity); } }); - console.log("config", this.config); - return this.configService.saveConfig(this.entityMapper, this.config.data); } private getEntity(viewId: string): EntityConstructor { @@ -64,7 +92,6 @@ export class ConfigMigrationService { .split("-") .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) .join(""); - console.log("Loading Entity", entityType, viewId); return ENTITY_MAP.get(entityType); } @@ -230,7 +257,6 @@ export class ConfigMigrationService { ["age", "EditAge"], ["datepicker", "EditDate"], ["entity-select", "EditEntityArray"], - ["select", "EditSelectable"], ]); columns.forEach((row) => row.forEach((formField) => { @@ -250,7 +276,11 @@ export class ConfigMigrationService { if (formField.id === "photoFile") { formField.id = "photo"; } - formField.edit = editMap.get(formField["input"]); + if (formField["input"] === "select") { + this.migrateSelectFormField(formField, entity); + } else { + formField.edit = editMap.get(formField["input"]); + } delete formField["input"]; this.addLabelToEntity(formField.label, formField.id, entity, "short"); } catch (e) { @@ -260,6 +290,43 @@ export class ConfigMigrationService { ); } + private migrateSelectFormField( + formField: FormFieldConfig, + entity: EntityConstructor + ) { + const selectableMap = new Map([ + ["warningLevel", "warning-levels"], + ["materialType", "materials"], + ["gender", "genders"], + ["hindi", "reading-levels"], + ["bengali", "reading-levels"], + ["english", "reading-levels"], + ["math", "math-levels"], + ]); + if (!selectableMap.has(formField.id)) { + const newEnum: ConfigurableEnumValue[] = [{ id: "", label: "" }].concat( + ...formField["additional"].map((option: string) => { + return { + label: option, + id: option, + }; + }) + ); + this.config.data[ + CONFIGURABLE_ENUM_CONFIG_PREFIX + formField.id + ] = newEnum; + console.warn( + `Automatically created enum "${formField.id}" with values:`, + newEnum + ); + selectableMap.set(formField.id, formField.id); + } + const propertySchema = entity.schema.get(formField.id); + propertySchema.dataType = "configurable-enum"; + propertySchema.innerDataType = selectableMap.get(formField.id); + delete formField["additional"]; + } + private migratePreviousSchoolsComponent(columns: FormFieldConfig[]) { if (columns) { columns.forEach((formField) => { diff --git a/src/app/core/config/config.ts b/src/app/core/config/config.ts index 3a56dad7dd..8853c0ba8b 100644 --- a/src/app/core/config/config.ts +++ b/src/app/core/config/config.ts @@ -1,4 +1,4 @@ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DatabaseField } from "../entity/database-field.decorator"; import { DatabaseEntity } from "../entity/database-entity.decorator"; diff --git a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts index b579350b56..cfe25050e5 100644 --- a/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts +++ b/src/app/core/configurable-enum/configurable-enum-datatype/configurable-enum-datatype.spec.ts @@ -18,7 +18,7 @@ import { ConfigurableEnumConfig, ConfigurableEnumValue, } from "../configurable-enum.interface"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { DatabaseField } from "../../entity/database-field.decorator"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { TestBed, waitForAsync } from "@angular/core/testing"; diff --git a/src/app/core/configurable-enum/configurable-enum.interface.ts b/src/app/core/configurable-enum/configurable-enum.interface.ts index 83735800af..6ca3054b5b 100644 --- a/src/app/core/configurable-enum/configurable-enum.interface.ts +++ b/src/app/core/configurable-enum/configurable-enum.interface.ts @@ -21,6 +21,11 @@ export interface ConfigurableEnumValue { */ label: string; + /** + * an optional color code which should be displayed + */ + color?: string; + /** * Optionally any number of additional properties specific to a certain enum collection. */ diff --git a/src/app/core/configurable-enum/configurable-enum.module.ts b/src/app/core/configurable-enum/configurable-enum.module.ts index 14c41c885a..97ad8db49a 100644 --- a/src/app/core/configurable-enum/configurable-enum.module.ts +++ b/src/app/core/configurable-enum/configurable-enum.module.ts @@ -4,6 +4,13 @@ import { ConfigService } from "../config/config.service"; import { EntitySchemaService } from "../entity/schema/entity-schema.service"; import { ConfigurableEnumDatatype } from "./configurable-enum-datatype/configurable-enum-datatype"; import { ConfigurableEnumDirective } from "./configurable-enum-directive/configurable-enum.directive"; +import { EditConfigurableEnumComponent } from "./edit-configurable-enum/edit-configurable-enum.component"; +import { DisplayConfigurableEnumComponent } from "./display-configurable-enum/display-configurable-enum.component"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatSelectModule } from "@angular/material/select"; +import { ReactiveFormsModule } from "@angular/forms"; +import { MatIconModule } from "@angular/material/icon"; +import { MatTooltipModule } from "@angular/material/tooltip"; /** * Provides a generic functionality to define enums (collections of selectable options) in the config database @@ -47,9 +54,24 @@ import { ConfigurableEnumDirective } from "./configurable-enum-directive/configu * {@link ConfigurableEnumDirective} similar to `*ngFor`. */ @NgModule({ - declarations: [ConfigurableEnumDirective], - imports: [CommonModule], + declarations: [ + ConfigurableEnumDirective, + EditConfigurableEnumComponent, + DisplayConfigurableEnumComponent, + ], + imports: [ + CommonModule, + MatFormFieldModule, + MatSelectModule, + ReactiveFormsModule, + MatIconModule, + MatTooltipModule, + ], exports: [ConfigurableEnumDirective], + entryComponents: [ + EditConfigurableEnumComponent, + DisplayConfigurableEnumComponent, + ], }) export class ConfigurableEnumModule { constructor( diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.spec.ts similarity index 93% rename from src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts rename to src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.spec.ts index 6b45cb75a0..abfb7e2db3 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.spec.ts +++ b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { DisplayConfigurableEnumComponent } from "./display-configurable-enum.component"; -import { Note } from "../../../../../child-dev-project/notes/model/note"; +import { Note } from "../../../child-dev-project/notes/model/note"; describe("DisplayConfigurableEnumComponent", () => { let component: DisplayConfigurableEnumComponent; diff --git a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts similarity index 73% rename from src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts rename to src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts index 8e8cd17f0a..1ee172540c 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component.ts +++ b/src/app/core/configurable-enum/display-configurable-enum/display-configurable-enum.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { ViewComponent } from "../view-component"; +import { ViewComponent } from "../../entity-components/entity-utils/view-components/view-component"; /** * This component displays a text attribute. diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.html similarity index 100% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.html rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.html diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.scss rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.scss diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts similarity index 89% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts index 72e17049c8..38b761ea49 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.spec.ts +++ b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.spec.ts @@ -1,10 +1,10 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { EditConfigurableEnumComponent } from "./edit-configurable-enum.component"; -import { EntityDetailsModule } from "../../../entity-details/entity-details.module"; +import { EntityDetailsModule } from "../../entity-components/entity-details/entity-details.module"; import { FormControl, FormGroup } from "@angular/forms"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { ConfigService } from "../../../../config/config.service"; +import { ConfigService } from "../../config/config.service"; describe("EditConfigurableEnumComponent", () => { let component: EditConfigurableEnumComponent; diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts similarity index 72% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts rename to src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts index 85431f66bf..5b9844b861 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component.ts +++ b/src/app/core/configurable-enum/edit-configurable-enum/edit-configurable-enum.component.ts @@ -1,6 +1,9 @@ import { Component } from "@angular/core"; -import { EditComponent, EditPropertyConfig } from "../edit-component"; -import { ConfigurableEnumValue } from "../../../../configurable-enum/configurable-enum.interface"; +import { + EditComponent, + EditPropertyConfig, +} from "../../entity-components/entity-utils/dynamic-form-components/edit-component"; +import { ConfigurableEnumValue } from "../configurable-enum.interface"; @Component({ selector: "app-edit-configurable-enum", diff --git a/src/app/core/database/query-data-source.ts b/src/app/core/database/query-data-source.ts index 9837e4259b..7c7d33e4f0 100644 --- a/src/app/core/database/query-data-source.ts +++ b/src/app/core/database/query-data-source.ts @@ -1,7 +1,7 @@ import { CollectionViewer, DataSource } from "@angular/cdk/collections"; import { BehaviorSubject, Observable } from "rxjs"; import { MatPaginator } from "@angular/material/paginator"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { Database } from "./database"; /** diff --git a/src/app/core/demo-data/demo-data-generator.ts b/src/app/core/demo-data/demo-data-generator.ts index 4d7393b36a..7967f88815 100644 --- a/src/app/core/demo-data/demo-data-generator.ts +++ b/src/app/core/demo-data/demo-data-generator.ts @@ -1,4 +1,4 @@ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Abstract base class for demo data generator services. diff --git a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts index e107a813bf..11995e0d3f 100644 --- a/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts +++ b/src/app/core/entity-components/entity-details/EntityDetailsConfig.ts @@ -1,24 +1,79 @@ -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; +/** + * The configuration for a entity details page + */ export interface EntityDetailsConfig { + /** + * The name of an icon which should be displayed next to the entity name. + * The name has to be a valid font-awesome icon name. + */ icon: string; + + /** + * The name of the entity (according to the ENTITY_TYPE). + */ entity: string; + + /** + * The configuration for the panels on this details page. + */ panels: Panel[]; } +/** + * A panel is a simple accordion that can be expanded and closed. + * It can hold multiple components. + */ export interface Panel { + /** + * The title of this panel. This should group the contained components. + */ title: string; + + /** + * The configurations for the components in this panel. + */ components: PanelComponent[]; } +/** + * The configuration for a component displayed inside a panel. + */ export interface PanelComponent { + /** + * An optional second title for only this component. + */ title: string; + + /** + * The name of the component according to the DYNAMIC_COMPONENT_MAP. + */ component: string; - config?: PanelConfig; + + /** + * A addition config which will be passed to the component. + */ + config?: any; } +/** + * This interface represents the config which will be created by the entity-details component and passed to each of + * the panel components. + */ export interface PanelConfig { + /** + * The full entity which is displayed in this details page. + */ entity: Entity; + + /** + * Whether this entity has been newly created. + */ creatingNew?: boolean; + + /** + * An additional config which has been defined in the PanelComponent. + */ config?: any; } diff --git a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts index e9b9746894..5ca121ed6c 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.spec.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.spec.ts @@ -11,7 +11,7 @@ import { MatNativeDateModule } from "@angular/material/core"; import { ActivatedRoute, Router } from "@angular/router"; import { RouterTestingModule } from "@angular/router/testing"; import { MatSnackBar } from "@angular/material/snack-bar"; -import { PanelConfig } from "./EntityDetailsConfig"; +import { EntityDetailsConfig, PanelConfig } from "./EntityDetailsConfig"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { User } from "../../user/user"; import { SessionService } from "../../session/session-service/session.service"; @@ -27,7 +27,7 @@ describe("EntityDetailsComponent", () => { let routeObserver: Subscriber; - const routeConfig = { + const routeConfig: EntityDetailsConfig = { icon: "child", entity: "Child", panels: [ diff --git a/src/app/core/entity-components/entity-details/entity-details.component.ts b/src/app/core/entity-components/entity-details/entity-details.component.ts index 99b60b3410..480626e8b1 100644 --- a/src/app/core/entity-components/entity-details/entity-details.component.ts +++ b/src/app/core/entity-components/entity-details/entity-details.component.ts @@ -8,7 +8,7 @@ import { Panel, PanelComponent, } from "./EntityDetailsConfig"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { School } from "../../../child-dev-project/schools/model/school"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { getUrlWithoutParams } from "../../../utils/utils"; @@ -38,8 +38,8 @@ export const ENTITY_MAP: Map> = new Map< /** * This component can be used to display a entity in more detail. * It groups subcomponents in panels. - * Any component can be used as a subcomponent. - * The subcomponents will be provided with the Entity object and the creating new status, as well as its static config. + * Any component from the DYNAMIC_COMPONENT_MAP can be used as a subcomponent. + * The subcomponents will be provided with the Entity object and the creating new status, as well as it's static config. */ @Component({ selector: "app-entity-details", diff --git a/src/app/core/entity-components/entity-details/form/form.component.spec.ts b/src/app/core/entity-components/entity-details/form/form.component.spec.ts index 102dd0ecd2..b0636faf09 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.spec.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.spec.ts @@ -43,7 +43,7 @@ describe("FormComponent", () => { const router = fixture.debugElement.injector.get(Router); spyOn(router, "navigate"); component.creatingNew = true; - await component.routeToEntity(testChild); + await component.saveClicked(testChild); expect(router.navigate).toHaveBeenCalledWith(["", testChild.getId()]); }); }); diff --git a/src/app/core/entity-components/entity-details/form/form.component.ts b/src/app/core/entity-components/entity-details/form/form.component.ts index 74b123d187..a7c5743771 100644 --- a/src/app/core/entity-components/entity-details/form/form.component.ts +++ b/src/app/core/entity-components/entity-details/form/form.component.ts @@ -1,26 +1,32 @@ import { Component } from "@angular/core"; import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; import { PanelConfig } from "../EntityDetailsConfig"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { getParentUrl } from "../../../../utils/utils"; import { Router } from "@angular/router"; +import { Location } from "@angular/common"; @Component({ selector: "app-form", - template: ``, }) +/** + * A simple wrapper function of the EntityFormComponent which can be used as a dynamic component + * e.g. as a panel for the EntityDetailsComponent. + */ export class FormComponent implements OnInitDynamicComponent { entity: Entity; columns: FormFieldConfig[][] = []; creatingNew = false; - constructor(private router: Router) {} + constructor(private router: Router, private location: Location) {} onInitFromDynamicConfig(config: PanelConfig) { this.entity = config.entity; @@ -30,9 +36,15 @@ export class FormComponent implements OnInitDynamicComponent { } } - routeToEntity(entity: Entity) { + saveClicked(entity: Entity) { if (this.creatingNew) { this.router.navigate([getParentUrl(this.router), entity.getId()]); } } + + cancelClicked() { + if (this.creatingNew) { + this.location.back(); + } + } } diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index 4276f2db25..fa807d40b6 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -5,6 +5,7 @@ import { FormBuilder } from "@angular/forms"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { EntityFormModule } from "./entity-form.module"; +import { Entity } from "../../entity/model/entity"; describe("EntityFormService", () => { let service: EntityFormService; @@ -27,4 +28,22 @@ describe("EntityFormService", () => { it("should be created", () => { expect(service).toBeTruthy(); }); + + it("should not save invalid entities", () => { + const entity = new Entity("initialId"); + spyOn(entity, "copy").and.returnValue(entity); + spyOn(entity, "assertValid").and.throwError(new Error()); + const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); + + expect(() => service.saveChanges(formGroup, entity)).toThrowError(); + }); + + it("should return updated entity if saving is successful", async () => { + const entity = new Entity("initialId"); + const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); + + const newEntity = await service.saveChanges(formGroup, entity); + + expect(newEntity.getId()).toBe("newId"); + }); }); diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 03cd49bf7f..e8f882c1a2 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -1,11 +1,15 @@ import { Injectable } from "@angular/core"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { FormFieldConfig } from "./entity-form/FormConfig"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; @Injectable() +/** + * This service provides helper functions for creating tables or forms for an entity as well as saving + * new changes correctly to the entity. + */ export class EntityFormService { constructor( private fb: FormBuilder, @@ -56,25 +60,37 @@ export class EntityFormService { const entitySchema = entity.getSchema(); formFields.forEach((formField) => { const propertySchema = entitySchema.get(formField.id); - formConfig[formField.id] = [entity[formField.id]]; - if (formField.required || propertySchema?.required) { - formConfig[formField.id].push(Validators.required); + // Only properties with a schema are editable + if (propertySchema) { + formConfig[formField.id] = [entity[formField.id]]; + if (formField.required || propertySchema?.required) { + formConfig[formField.id].push(Validators.required); + } } }); return this.fb.group(formConfig); } - public saveChanges(form: FormGroup, entity: Entity): Promise { + /** + * This function applies the changes of the formGroup to the entity. + * If the form is invalid or the entity does not pass validation after applying the changes, an error will be thrown. + * The input entity will not be modified but a copy of it will be returned in case of success. + * @param form The formGroup holding the changes + * @param entity The entity on which the changes should be applied. + * @returns a copy of the input entity with the changes from the form group + */ + public saveChanges(form: FormGroup, entity: T): Promise { this.checkFormValidity(form); - const entityConstructor = entity.getConstructor(); - entityConstructor.validateForm(form); + const entityCopy = entity.copy() as T; + this.assignFormValuesToEntity(form, entityCopy); + entityCopy.assertValid(); - this.assignFormValuesToEntity(form, entity); - return this.entityMapper.save(entity).catch((err) => { - throw new Error( - `Could not save ${entityConstructor.ENTITY_TYPE}: ${err}` - ); - }); + return this.entityMapper + .save(entityCopy) + .then(() => entityCopy) + .catch((err) => { + throw new Error(`Could not save ${entity.getType()}: ${err}`); + }); } private checkFormValidity(form: FormGroup) { diff --git a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts index 7699326264..a8988dfaf4 100644 --- a/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts +++ b/src/app/core/entity-components/entity-form/entity-form/FormConfig.ts @@ -1,13 +1,32 @@ +/** + * The general configuration for fields in tables and forms. + * This defines which property is displayed and how it should be displayed. + * Most information does not need to be provided if a property with schema definitions is displayed. + */ export interface FormFieldConfig { - view?: string; - - edit?: string; - /** * The id of the entity which should be accessed */ id: string; + /** + * Defines the component that should display this form field. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the component specified in the schema for this property or the default component of the + * property's datatype will be used. + */ + view?: string; + + /** + * Defines the component which allows to edit this form field. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the component specified in the schema for this property or the default component of the + * property's datatype will be used. If nothing is found, the form field will be displayed in the "view" mode. + */ + edit?: string; + /** * A label or description of the expected input */ @@ -19,13 +38,39 @@ export interface FormFieldConfig { */ required?: boolean; + /** + * An additional description which explains this form field. + * + * If nothing is specified, the property schemas "description" field will be used. + */ tooltip?: string; - forTable?: boolean; - + /** + * When set to true, the sorting of this column will be disabled. + * Should be used when the sorting will not work correctly/does not make sense. + * E.g. when displaying a list of entities + */ noSorting?: boolean; + /** + * Further information for the final view/edit component. + * This is necessary when displaying columns where no schema is available, e.g. to display "readonly-functions". + * This should only be used in cases where a property without schema information is displayed. + */ additional?: any; + /** + * visibleFrom The minimal screen size where the column is shown. + * screen size classes: xs 'screen and (max-width: 599px)' + * sm 'screen and (min-width: 600px) and (max-width: 959px)' + * md 'screen and (min-width: 960px) and (max-width: 1279px)' + * lg 'screen and (min-width: 1280px) and (max-width: 1919px)' + * xl 'screen and (min-width: 1920px) and (max-width: 5000px)' + */ visibleFrom?: string; + + /** + * A internal flag that will be automatically set in the entity subrecord in order to adapt the view/edit components. + */ + forTable?: boolean; } diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts index 26f6c9d711..8daaf1657d 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import { EntityFormComponent } from "./entity-form.component"; import { ChildPhotoService } from "../../../../child-dev-project/children/child-photo-service/child-photo.service"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { User } from "../../../user/user"; import { RouterTestingModule } from "@angular/router/testing"; @@ -16,6 +16,7 @@ import { Child } from "../../../../child-dev-project/children/model/child"; import { EntityFormModule } from "../entity-form.module"; import { FormBuilder } from "@angular/forms"; import { MatSnackBarModule } from "@angular/material/snack-bar"; +import { EntityFormService } from "../entity-form.service"; describe("EntityFormComponent", () => { let component: EntityFormComponent; @@ -84,7 +85,7 @@ describe("EntityFormComponent", () => { it("should emit notification when a child is saved", (done) => { spyOnProperty(component.form, "valid").and.returnValue(true); const subscription = component.onSave.subscribe((child) => { - expect(child).toBe(testChild); + expect(child).toEqual(testChild); subscription.unsubscribe(); done(); }); @@ -92,21 +93,17 @@ describe("EntityFormComponent", () => { component.save(); }); - it("reports error when form is invalid", () => { - const alertService = fixture.debugElement.injector.get(AlertService); - spyOn(alertService, "addDanger"); - spyOnProperty(component.form, "invalid").and.returnValue(true); + it("should show an warning alert when form service rejects saving", async () => { + const alertService = TestBed.inject(AlertService); + spyOn(alertService, "addWarning"); + const entityFormService = TestBed.inject(EntityFormService); + spyOn(entityFormService, "saveChanges").and.rejectWith( + new Error("error message") + ); - return expectAsync(component.save()).toBeRejected(); - }); - - it("logs error when saving fails", () => { - const alertService = fixture.debugElement.injector.get(AlertService); - spyOn(alertService, "addDanger"); - spyOnProperty(component.form, "valid").and.returnValue(true); - mockEntityMapper.save.and.rejectWith("error"); + await component.save(); - return expectAsync(component.save()).toBeRejected(); + expect(alertService.addWarning).toHaveBeenCalledWith("error message"); }); it("should add column definitions from property schema", () => { diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index bca16ee340..1b8bd940ff 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -1,18 +1,41 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { OperationType } from "../../../permissions/entity-permissions.service"; import { FormFieldConfig } from "./FormConfig"; import { FormGroup } from "@angular/forms"; import { EntityFormService } from "../entity-form.service"; +import { AlertService } from "../../../alerts/alert.service"; @Component({ selector: "app-entity-form", templateUrl: "./entity-form.component.html", styleUrls: ["./entity-form.component.scss"], }) +/** + * A general purpose form component for displaying and editing entities. + * It uses the FormFieldConfig interface for building the form fields but missing information are also fetched from + * the entity's schema definitions. Properties with sufficient schema information can be displayed by only providing + * the name of this property (and not an FormFieldConfig object). + * + * This component can be used directly or in a popup. + * Inside the entity details component use the FormComponent which is part of the DYNAMIC_COMPONENT_MAP. + */ export class EntityFormComponent implements OnInit { + /** + * The entity which should be displayed and edited + */ @Input() entity: Entity; - @Input() creatingNew = false; + + /** + * Whether the form should be opened in editing mode or not + */ + @Input() editing = false; + + /** + * The form field definitions. Either as a string or as a FormFieldConfig object. + * Missing information will be fetched from the entity schema definition. + * @param columns The columns which should be displayed + */ @Input() set columns(columns: (FormFieldConfig | string)[][]) { this._columns = columns.map((row) => row.map((field) => { @@ -26,16 +49,27 @@ export class EntityFormComponent implements OnInit { } _columns: FormFieldConfig[][] = []; + /** + * This will be emitted whenever changes have been successfully saved to the entity. + */ @Output() onSave = new EventEmitter(); + /** + * This will be emitted whenever the cancel button is pressed. + */ + @Output() onCancel = new EventEmitter(); + operationType = OperationType; form: FormGroup; - constructor(private entityFormService: EntityFormService) {} + constructor( + private entityFormService: EntityFormService, + private alertService: AlertService + ) {} ngOnInit() { this.buildFormConfig(); - if (this.creatingNew) { + if (this.editing) { this.switchEdit(); } } @@ -49,12 +83,20 @@ export class EntityFormComponent implements OnInit { } async save(): Promise { - await this.entityFormService.saveChanges(this.form, this.entity); - this.switchEdit(); - this.onSave.emit(this.entity); + try { + this.entity = await this.entityFormService.saveChanges( + this.form, + this.entity + ); + this.onSave.emit(this.entity); + this.switchEdit(); + } catch (err) { + this.alertService.addWarning(err.message); + } } cancel() { + this.onCancel.emit(); this.buildFormConfig(); } diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts index 8ed43ba823..d13b44d79a 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts @@ -65,6 +65,10 @@ const cols = [ id: "name", required: true, }, + { + id: "projectNumber", + edit: "EditNumber", + }, { edit: "EditLongText", id: "additionalInfo", @@ -76,17 +80,6 @@ const cols = [ label: "Is active", }, { id: "gender" }, - { - edit: "EditSelectable", - id: "health_vaccinationStatus", - label: "Vaccination Status", - additional: [ - "Good", - "Vaccination Due", - "Needs Checking", - "No Card/Information", - ], - }, ], [ { diff --git a/src/app/core/entity-components/entity-list/EntityListConfig.ts b/src/app/core/entity-components/entity-list/EntityListConfig.ts index 147686eeff..fdf1f5207d 100644 --- a/src/app/core/entity-components/entity-list/EntityListConfig.ts +++ b/src/app/core/entity-components/entity-list/EntityListConfig.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { FilterSelectionOption } from "../../filter/filter-selection/filter-selection"; import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; diff --git a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts index 1d4255da32..e8f039f9ac 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.spec.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.spec.ts @@ -5,7 +5,7 @@ import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { RouterTestingModule } from "@angular/router/testing"; import { SimpleChange } from "@angular/core"; import { BooleanFilterConfig, EntityListConfig } from "./EntityListConfig"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { User } from "../../user/user"; import { SessionService } from "../../session/session-service/session.service"; diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 42a5d0f9df..14453497a8 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -16,14 +16,12 @@ import { FilterConfig, GroupConfig, } from "./EntityListConfig"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { OperationType } from "../../permissions/entity-permissions.service"; import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; -import { - FilterComponentSettings, - FilterGeneratorService, -} from "./filter-generator.service"; +import { FilterGeneratorService } from "./filter-generator.service"; +import { FilterComponentSettings } from "./filter-component.settings"; /** * This component allows to create a full blown table with pagination, filtering, searching and grouping. @@ -89,7 +87,7 @@ export class EntityListComponent ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty("listConfig")) { this.listName = this.listConfig.title; - this.initColumns(); + this.addColumnsFromColumnGroups(); this.initColumnGroups(this.listConfig.columnGroups); this.filtersConfig = this.listConfig.filters || []; this.displayColumnGroup(this.defaultColumnGroup); @@ -101,21 +99,20 @@ export class EntityListComponent this.loadUrlParams(); } - private initColumns() { + private addColumnsFromColumnGroups() { this.columns = this.listConfig.columns || []; - const uniqueColumnIds = new Set(); - this.listConfig?.columnGroups?.groups?.forEach((group) => - group.columns.forEach((column) => uniqueColumnIds.add(column)) - ); - this.columns.push( - ...new Array(...uniqueColumnIds).filter( - (columnId) => - !this.columns.some((column) => - typeof column === "string" - ? column === columnId - : column.id === columnId - ) - ) + this.listConfig.columnGroups?.groups?.forEach((group) => + group.columns + .filter( + (columnId) => + !this.columns.some((column) => + // Check if the column is already defined as object or string + typeof column === "string" + ? column === columnId + : column.id === columnId + ) + ) + .forEach((column) => this.columns.push(column)) ); } diff --git a/src/app/core/entity-components/entity-list/filter-component.settings.ts b/src/app/core/entity-components/entity-list/filter-component.settings.ts new file mode 100644 index 0000000000..22e3b68ecd --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-component.settings.ts @@ -0,0 +1,28 @@ +import { FilterSelection } from "../../filter/filter-selection/filter-selection"; + +/** + * A simple interface which holds all required information to display and use a filter. + */ +export interface FilterComponentSettings { + /** + * The filter selection which handles the logic for filtering the data. + */ + filterSettings: FilterSelection; + + /** + * The selected option of this filter. + */ + selectedOption?: string; + + /** + * The way in which the filter should be displayed. + * Possible values: "dropdown" which will render it as a dropdown selection. + * Default to buttons next to each other. + */ + display?: string; + + /** + * The label for this filter. + */ + label?: string; +} diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index bc87a69d95..ffc733bb31 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -9,7 +9,7 @@ import { PrebuiltFilterConfig, } from "./EntityListConfig"; import { ENTITY_MAP } from "../entity-details/entity-details.component"; -import { Entity, EntityConstructor } from "../../entity/entity"; +import { Entity, EntityConstructor } from "../../entity/model/entity"; import { CONFIGURABLE_ENUM_CONFIG_PREFIX, ConfigurableEnumConfig, @@ -18,13 +18,7 @@ import { ConfigService } from "../../config/config.service"; import { LoggingService } from "../../logging/logging.service"; import { EntityMapperService } from "../../entity/entity-mapper.service"; import { EntitySchemaField } from "../../entity/schema/entity-schema-field"; - -export interface FilterComponentSettings { - filterSettings: FilterSelection; - selectedOption?: string; - display?: string; - label?: string; -} +import { FilterComponentSettings } from "./filter-component.settings"; @Injectable({ providedIn: "root", diff --git a/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts b/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts index 276f554a8b..3282e0297e 100644 --- a/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts +++ b/src/app/core/entity-components/entity-list/list-filter/list-filter.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { FilterSelection } from "../../../filter/filter-selection/filter-selection"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; @Component({ selector: "app-list-filter", diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html index 52769217e6..9af27e5d0f 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.html @@ -34,7 +34,7 @@ }" > { expect(sortedIds).toEqual(["0", "3", "1", "2"]); }); - it("should log an error when the column definition can not be initialized", () => { - const alertService = TestBed.inject(AlertService); - spyOn(alertService, "addWarning"); + it("should log a warning when the column definition can not be initialized", () => { + const loggingService = TestBed.inject(LoggingService); + spyOn(loggingService, "warn"); component.records = [new Child()]; component.columns = [ { @@ -231,7 +232,7 @@ describe("EntitySubrecordComponent", () => { component.ngOnChanges({ columns: null }); - expect(alertService.addWarning).toHaveBeenCalled(); + expect(loggingService.warn).toHaveBeenCalled(); }); it("should create a formGroup when editing a row", () => { @@ -249,23 +250,24 @@ describe("EntitySubrecordComponent", () => { expect(formGroup.enabled).toBeTrue(); }); - it("should correctly save changes to a entity", fakeAsync(() => { + it("should correctly save changes to an entity", fakeAsync(() => { mockEntityMapper.save.and.resolveTo(); const fb = TestBed.inject(FormBuilder); const child = new Child(); child.name = "Old Name"; const formGroup = fb.group({ name: "New Name", - gender: Gender.FEMALE, + gender: genders[2], }); + const tableRow = { record: child, formGroup: formGroup }; - component.save({ record: child, formGroup: formGroup }); + component.save(tableRow); tick(); - expect(mockEntityMapper.save).toHaveBeenCalledWith(child); - expect(child.name).toBe("New Name"); - expect(child.gender).toBe(Gender.FEMALE); - expect(formGroup.disabled).toBeTrue(); + expect(mockEntityMapper.save).toHaveBeenCalledWith(tableRow.record); + expect(tableRow.record.name).toBe("New Name"); + expect(tableRow.record.gender).toBe(genders[2]); + expect(tableRow.formGroup.disabled).toBeTrue(); })); it("should show a error message when saving fails", fakeAsync(() => { @@ -276,7 +278,7 @@ describe("EntitySubrecordComponent", () => { const alertService = TestBed.inject(AlertService); spyOn(alertService, "addDanger"); - component.save({ formGroup: null, record: null }); + component.save({ formGroup: null, record: new Child() }); tick(); expect(alertService.addDanger).toHaveBeenCalledWith("Form invalid"); @@ -332,7 +334,7 @@ describe("EntitySubrecordComponent", () => { expect(component.records).toEqual([child]); expect(component.recordsDataSource.data).toContain({ record: child }); - expect(showEntitySpy).toHaveBeenCalledWith(child, true); + expect(showEntitySpy).toHaveBeenCalledWith(child); })); it("should notify when an entity is clicked", (done) => { diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 7f1b50fccd..5cc91b59db 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -11,7 +11,7 @@ import { MatTableDataSource } from "@angular/material/table"; import { MediaChange, MediaObserver } from "@angular/flex-layout"; import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { AlertService } from "../../../alerts/alert.service"; import { Subscription } from "rxjs"; @@ -21,6 +21,7 @@ import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { EntityFormService } from "../../entity-form/entity-form.service"; import { MatDialog } from "@angular/material/dialog"; import { EntityFormComponent } from "../../entity-form/entity-form/entity-form.component"; +import { LoggingService } from "../../../logging/logging.service"; export interface TableRow { record: T; @@ -68,6 +69,9 @@ export class EntitySubrecordComponent implements OnChanges { */ @Input() newRecordFactory: () => T; + /** + * Whether the rows of the table are inline editable and new entries can be created through the "+" button. + */ @Input() editable: boolean = true; /** columns displayed in the template's table */ @@ -90,7 +94,8 @@ export class EntitySubrecordComponent implements OnChanges { private alertService: AlertService, private media: MediaObserver, private entityFormService: EntityFormService, - private dialog: MatDialog + private dialog: MatDialog, + private loggingService: LoggingService ) { this.mediaSubscription = this.media .asObservable() @@ -103,10 +108,13 @@ export class EntitySubrecordComponent implements OnChanges { }); } - @Input() showEntity = (entity: Entity, creatingNew = false) => - this.showEntityInForm(entity, creatingNew); + /** + * A function which should be executed when a row is clicked or a new entity created. + * @param entity The newly created or clicked entity. + */ + @Input() showEntity = (entity: T) => this.showEntityInForm(entity); - /** function returns the background color for each entry*/ + /** function returns the background color for each row*/ @Input() getBackgroundColor?: (rec: T) => string = (rec: T) => rec.getColor(); /** @@ -143,7 +151,7 @@ export class EntitySubrecordComponent implements OnChanges { .map((col) => (typeof col === "object" ? col.id : col)) .join(""); } catch (err) { - this.alertService.addWarning(`Error creating form definitions: ${err}`); + this.loggingService.warn(`Error creating form definitions: ${err}`); } } this.recordsDataSource.data = this.records.map((rec) => { @@ -198,7 +206,10 @@ export class EntitySubrecordComponent implements OnChanges { */ async save(row: TableRow) { try { - await this.entityFormService.saveChanges(row.formGroup, row.record); + row.record = await this.entityFormService.saveChanges( + row.formGroup, + row.record + ); row.formGroup.disable(); } catch (err) { this.alertService.addDanger(err.message); @@ -262,9 +273,7 @@ export class EntitySubrecordComponent implements OnChanges { this.recordsDataSource.data = [{ record: newRecord }].concat( this.recordsDataSource.data ); - this._entityMapper - .save(newRecord) - .then(() => this.showEntity(newRecord, true)); + this._entityMapper.save(newRecord).then(() => this.showEntity(newRecord)); } /** @@ -277,20 +286,26 @@ export class EntitySubrecordComponent implements OnChanges { } } - private showEntityInForm(entity: Entity, creatingNew = false) { + private showEntityInForm(entity: T) { const dialogRef = this.dialog.open(EntityFormComponent, { width: "80%", }); - const columnsCopy = []; - this._columns.forEach((col) => { - const newCol = {}; - Object.assign(newCol, col); - columnsCopy.push([newCol]); - }); - dialogRef.componentInstance.columns = columnsCopy; + // Making a copy of the editable columns before assigning them + dialogRef.componentInstance.columns = this._columns + .filter((col) => col.edit) + .map((col) => [Object.assign({}, col)]); dialogRef.componentInstance.entity = entity; - dialogRef.componentInstance.creatingNew = creatingNew; - dialogRef.componentInstance.onSave.subscribe(() => dialogRef.close()); + dialogRef.componentInstance.editing = true; + dialogRef.componentInstance.onSave.subscribe((updatedEntity: T) => { + dialogRef.close(); + // Trigger the change detection + const rowIndex = this.recordsDataSource.data.findIndex( + (row) => row.record === entity + ); + this.recordsDataSource.data[rowIndex] = { record: updatedEntity }; + this.recordsDataSource._updateChangeSubscription(); + }); + dialogRef.componentInstance.onCancel.subscribe(() => dialogRef.close()); } /** diff --git a/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts index 9e4698b636..abcb5db41f 100644 --- a/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts +++ b/src/app/core/entity-components/entity-subrecord/list-paginator/list-paginator.component.ts @@ -6,7 +6,7 @@ import { SimpleChanges, AfterViewInit, } from "@angular/core"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { MatPaginator, PageEvent } from "@angular/material/paginator"; import { MatTableDataSource } from "@angular/material/table"; import { User } from "../../../user/user"; diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts index cd8a0bb50d..4c50b498b0 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-component.ts @@ -3,12 +3,30 @@ import { AbstractControl, FormControl } from "@angular/forms"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { EntitySchemaField } from "../../../entity/schema/entity-schema-field"; +/** + * The interface for the configuration which is created by the form- or the entity-subrecord-component. + */ export interface EditPropertyConfig { + /** + * The configuration for this form field. + */ formFieldConfig: FormFieldConfig; + + /** + * If available, the schema for the property which is displayed in this field. + */ propertySchema: EntitySchemaField; + + /** + * The form control for this field which is part of a form group of the table/form component. + */ formControl: AbstractControl; } +/** + * A simple extension of the Form control which allows to access the form type-safe. + * refers to the type of the value which is managed in this control. + */ export class TypedFormControl extends FormControl { value: T; setValue( @@ -24,10 +42,29 @@ export class TypedFormControl extends FormControl { } } +/** + * A simple helper class which sets up all the required information for edit-components. + * refers to the type of the value which is processed in the component. + */ export abstract class EditComponent implements OnInitDynamicComponent { + /** + * The tooltip to be displayed. + */ tooltip: string; + + /** + * The name of the form control. + */ formControlName: string; + + /** + * A label for this component. + */ label: string; + + /** + * The typed form control. + */ formControl: TypedFormControl; onInitFromDynamicConfig(config: EditPropertyConfig) { diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts index 5853590e85..ef88542e17 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-entity-array/edit-entity-array.component.ts @@ -1,9 +1,9 @@ import { Component } from "@angular/core"; import { EditComponent, EditPropertyConfig } from "../edit-component"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Component({ - selector: "app-edit-selectable-entity", + selector: "app-edit-entity-array", templateUrl: "./edit-entity-array.component.html", styleUrls: ["./edit-entity-array.component.scss"], }) diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html new file mode 100644 index 0000000000..1b81086035 --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.html @@ -0,0 +1,14 @@ + + + + Only numbers are allowed + + + This field is required + + diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.scss similarity index 100% rename from src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.scss rename to src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.scss diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts new file mode 100644 index 0000000000..2c0c34d38a --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.spec.ts @@ -0,0 +1,50 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; + +import { EditNumberComponent } from "./edit-number.component"; +import { FormControl, FormGroup, ReactiveFormsModule } from "@angular/forms"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatInputModule } from "@angular/material/input"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; + +describe("EditNumberComponent", () => { + let component: EditNumberComponent; + let fixture: ComponentFixture; + let formGroup: FormGroup; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + NoopAnimationsModule, + ], + declarations: [EditNumberComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditNumberComponent); + component = fixture.componentInstance; + const formControl = new FormControl(); + formGroup = new FormGroup({ testProperty: formControl }); + component.onInitFromDynamicConfig({ + formControl: formControl, + propertySchema: {}, + formFieldConfig: { id: "testProperty" }, + }); + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + it("should only allow valid entries", () => { + component.formControl.setValue("one" as any); + expect(formGroup.invalid).toBeTrue(); + + component.formControl.setValue("1" as any); + expect(formGroup.valid).toBeTrue(); + }); +}); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts new file mode 100644 index 0000000000..636a883c8c --- /dev/null +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component.ts @@ -0,0 +1,20 @@ +import { Component } from "@angular/core"; +import { EditComponent, EditPropertyConfig } from "../edit-component"; +import { Validators } from "@angular/forms"; + +@Component({ + selector: "app-edit-number", + templateUrl: "./edit-number.component.html", + styleUrls: ["./edit-number.component.scss"], +}) +export class EditNumberComponent extends EditComponent { + onInitFromDynamicConfig(config: EditPropertyConfig) { + super.onInitFromDynamicConfig(config); + const newValidators = [Validators.pattern("[0-9]*")]; + if (this.formControl.validator) { + newValidators.push(this.formControl.validator); + } + this.formControl.setValidators(newValidators); + this.formControl.updateValueAndValidity(); + } +} diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html index 3e301112f4..399b989829 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-percentage/edit-percentage.component.html @@ -1,7 +1,12 @@ - + - Only numbers are allowed in this field + Only numbers are allowed Must be equal or smaller 100 (%) diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html deleted file mode 100644 index 3be0e10e99..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - {{ label }} - - - - {{ o.label ? o.label : o }} - - - - diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts deleted file mode 100644 index ffcc700f50..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ComponentFixture, TestBed } from "@angular/core/testing"; - -import { EditSelectableComponent } from "./edit-selectable.component"; -import { EntityDetailsModule } from "../../../entity-details/entity-details.module"; -import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { FormControl, FormGroup } from "@angular/forms"; - -describe("EditSelectableComponent", () => { - let component: EditSelectableComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [EntityDetailsModule, NoopAnimationsModule], - declarations: [EditSelectableComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(EditSelectableComponent); - component = fixture.componentInstance; - const formControl = new FormControl(); - const formGroup = new FormGroup({}); - component.formControlName = "testControl"; - component.formControl = formControl; - formGroup.registerControl(component.formControlName, formControl); - fixture.detectChanges(); - }); - - it("should create", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts deleted file mode 100644 index f0b529e9b8..0000000000 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from "@angular/core"; -import { EditComponent, EditPropertyConfig } from "../edit-component"; - -@Component({ - selector: "app-edit-selectable", - templateUrl: "./edit-selectable.component.html", - styleUrls: ["./edit-selectable.component.scss"], -}) -export class EditSelectableComponent extends EditComponent { - options: (string | { label: string; value: string })[]; - onInitFromDynamicConfig(config: EditPropertyConfig) { - super.onInitFromDynamicConfig(config); - this.options = - config.formFieldConfig.additional || config.propertySchema.additional; - } -} diff --git a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts index 1915a3c13a..336a83e316 100644 --- a/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/dynamic-form-components/edit-single-entity/edit-single-entity.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { EditComponent, EditPropertyConfig } from "../edit-component"; import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; @Component({ selector: "app-edit-single-entity", diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts index 61c2a2102d..15abdaa88e 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.spec.ts @@ -10,7 +10,7 @@ import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatFormFieldModule } from "@angular/material/form-field"; import { MatChipsModule } from "@angular/material/chips"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; import { ReactiveFormsModule } from "@angular/forms"; import { mockEntityMapper } from "../../../entity/mock-entity-mapper-service"; import { User } from "../../../user/user"; diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts index 451f017ce5..3e3524f463 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.ts @@ -9,7 +9,7 @@ import { SimpleChanges, } from "@angular/core"; import { ENTER, COMMA } from "@angular/cdk/keycodes"; -import { Entity, EntityConstructor } from "../../../entity/entity"; +import { Entity, EntityConstructor } from "../../../entity/model/entity"; import { EntityMapperService } from "../../../entity/entity-mapper.service"; import { BehaviorSubject, Observable } from "rxjs"; import { FormControl } from "@angular/forms"; diff --git a/src/app/core/entity-components/entity-utils/entity-utils.module.ts b/src/app/core/entity-components/entity-utils/entity-utils.module.ts index 8fb6e2a2de..a49b63d658 100644 --- a/src/app/core/entity-components/entity-utils/entity-utils.module.ts +++ b/src/app/core/entity-components/entity-utils/entity-utils.module.ts @@ -1,9 +1,7 @@ import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; -import { EditConfigurableEnumComponent } from "./dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; import { EditTextComponent } from "./dynamic-form-components/edit-text/edit-text.component"; import { EditDateComponent } from "./dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "./dynamic-form-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "./dynamic-form-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "./dynamic-form-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "./dynamic-form-components/edit-long-text/edit-long-text.component"; @@ -15,7 +13,6 @@ import { DisplayEntityComponent } from "./view-components/display-entity/display import { DisplayEntityArrayComponent } from "./view-components/display-entity-array/display-entity-array.component"; import { DisplayTextComponent } from "./view-components/display-text/display-text.component"; import { DisplayDateComponent } from "./view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "./view-components/display-configurable-enum/display-configurable-enum.component"; import { DisplayCheckmarkComponent } from "./view-components/display-checkmark/display-checkmark.component"; import { ReadonlyFunctionComponent } from "./view-components/readonly-function/readonly-function.component"; import { DisplayPercentageComponent } from "./view-components/display-percentage/display-percentage.component"; @@ -33,13 +30,13 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; import { EntitySelectComponent } from "./entity-select/entity-select.component"; import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { MatChipsModule } from "@angular/material/chips"; +import { EditNumberComponent } from "./dynamic-form-components/edit-number/edit-number.component"; +import { EntityFunctionPipe } from "./view-components/readonly-function/entity-function.pipe"; @NgModule({ declarations: [ - EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, - EditSelectableComponent, EditAgeComponent, EditBooleanComponent, EditLongTextComponent, @@ -51,12 +48,13 @@ import { MatChipsModule } from "@angular/material/chips"; DisplayEntityArrayComponent, DisplayTextComponent, DisplayDateComponent, - DisplayConfigurableEnumComponent, DisplayCheckmarkComponent, ReadonlyFunctionComponent, DisplayPercentageComponent, DisplayUnitComponent, EntitySelectComponent, + EditNumberComponent, + EntityFunctionPipe, ], imports: [ CommonModule, @@ -74,10 +72,8 @@ import { MatChipsModule } from "@angular/material/chips"; MatChipsModule, ], entryComponents: [ - EditConfigurableEnumComponent, EditTextComponent, EditDateComponent, - EditSelectableComponent, EditAgeComponent, EditBooleanComponent, EditLongTextComponent, @@ -89,11 +85,11 @@ import { MatChipsModule } from "@angular/material/chips"; DisplayEntityArrayComponent, DisplayTextComponent, DisplayDateComponent, - DisplayConfigurableEnumComponent, DisplayCheckmarkComponent, ReadonlyFunctionComponent, DisplayPercentageComponent, DisplayUnitComponent, + EditNumberComponent, ], exports: [DisplayEntityComponent, EntitySelectComponent], }) diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html index ff5a2971d7..df083b481d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.html @@ -1,4 +1,4 @@ - + -{{ entities.length }} in total +{{ entity[property]?.length }} in total diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts index fadb5775a0..db9b184dec 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.spec.ts @@ -3,6 +3,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { DisplayEntityArrayComponent } from "./display-entity-array.component"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { Child } from "../../../../../child-dev-project/children/model/child"; +import { Note } from "../../../../../child-dev-project/notes/model/note"; describe("DisplayEntityArrayComponent", () => { let component: DisplayEntityArrayComponent; @@ -21,6 +22,7 @@ describe("DisplayEntityArrayComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(DisplayEntityArrayComponent); component = fixture.componentInstance; + component.onInitFromDynamicConfig({ entity: new Note(), id: "children" }); fixture.detectChanges(); }); diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts index c4e448230b..706fd772e7 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity-array/display-entity-array.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { ViewComponent } from "../view-component"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; @@ -11,22 +11,25 @@ import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; styleUrls: ["./display-entity-array.component.scss"], }) export class DisplayEntityArrayComponent extends ViewComponent { - entities: Entity[] = []; + readonly aggregationThreshold = 5; + entities: Entity[]; constructor(private entityMapper: EntityMapperService) { super(); } async onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); - const entityType = this.entity.getSchema().get(this.property).additional; - const entityConstructor = ENTITY_MAP.get(entityType); - if (!entityConstructor) { - throw new Error(`Could not find type ${entityType} in ENTITY_MAP`); - } const entityIds: string[] = this.entity[this.property] || []; - const entityPromises = entityIds.map((entityId) => - this.entityMapper.load(entityConstructor, entityId) - ); - this.entities = await Promise.all(entityPromises); + if (entityIds.length < this.aggregationThreshold) { + const entityType = this.entity.getSchema().get(this.property).additional; + const entityConstructor = ENTITY_MAP.get(entityType); + if (!entityConstructor) { + throw new Error(`Could not find type ${entityType} in ENTITY_MAP`); + } + const entityPromises = entityIds.map((entityId) => + this.entityMapper.load(entityConstructor, entityId) + ); + this.entities = await Promise.all(entityPromises); + } } } diff --git a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts index 43763f00fa..c393bac85e 100644 --- a/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/display-entity/display-entity.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from "@angular/core"; -import { Entity } from "../../../../entity/entity"; +import { Entity } from "../../../../entity/model/entity"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { EntityMapperService } from "../../../../entity/entity-mapper.service"; import { ENTITY_MAP } from "../../../entity-details/entity-details.component"; diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts new file mode 100644 index 0000000000..3bb9daf5bd --- /dev/null +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.spec.ts @@ -0,0 +1,8 @@ +import { EntityFunctionPipe } from "./entity-function.pipe"; + +describe("EntityFunctionPipe", () => { + it("create an instance", () => { + const pipe = new EntityFunctionPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts new file mode 100644 index 0000000000..5ac8760a46 --- /dev/null +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/entity-function.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { Entity } from "../../../../entity/model/entity"; + +@Pipe({ + name: "entityFunction", +}) +/** + * A simple pipe which passes the input entity to the input function. + * This reduces the change detection cycles, because the function is only re-calculated once the entity changed. + */ +export class EntityFunctionPipe implements PipeTransform { + transform(value: Entity, func?: (entity: Entity) => any): any { + return func(value); + } +} diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html index 1ecdf3cae4..fca05ba09d 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.html @@ -1 +1 @@ -{{ displayFunction(entity) }} +{{ entity | entityFunction: displayFunction }} diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts index b37d525bf1..2d513b65d8 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.spec.ts @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ReadonlyFunctionComponent } from "./readonly-function.component"; import { Child } from "../../../../../child-dev-project/children/model/child"; +import { EntityFunctionPipe } from "./entity-function.pipe"; describe("ReadonlyFunctionComponent", () => { let component: ReadonlyFunctionComponent; @@ -9,7 +10,7 @@ describe("ReadonlyFunctionComponent", () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ReadonlyFunctionComponent], + declarations: [ReadonlyFunctionComponent, EntityFunctionPipe], }).compileComponents(); }); diff --git a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts index 07f2b1883f..f86769e355 100644 --- a/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/readonly-function/readonly-function.component.ts @@ -1,6 +1,7 @@ import { Component } from "@angular/core"; import { ViewPropertyConfig } from "../../../entity-list/EntityListConfig"; import { ViewComponent } from "../view-component"; +import { Entity } from "../../../../entity/model/entity"; @Component({ selector: "app-readonly-function", @@ -8,7 +9,7 @@ import { ViewComponent } from "../view-component"; styleUrls: ["./readonly-function.component.scss"], }) export class ReadonlyFunctionComponent extends ViewComponent { - displayFunction: (Entity) => any; + displayFunction: (entity: Entity) => any; onInitFromDynamicConfig(config: ViewPropertyConfig) { super.onInitFromDynamicConfig(config); this.displayFunction = config.config; diff --git a/src/app/core/entity-components/entity-utils/view-components/view-component.ts b/src/app/core/entity-components/entity-utils/view-components/view-component.ts index b6c73f4253..4011a22759 100644 --- a/src/app/core/entity-components/entity-utils/view-components/view-component.ts +++ b/src/app/core/entity-components/entity-utils/view-components/view-component.ts @@ -1,6 +1,6 @@ import { OnInitDynamicComponent } from "../../../view/dynamic-components/on-init-dynamic-component.interface"; import { ViewPropertyConfig } from "../../entity-list/EntityListConfig"; -import { Entity } from "../../../entity/entity"; +import { Entity } from "../../../entity/model/entity"; export abstract class ViewComponent implements OnInitDynamicComponent { entity: Entity; diff --git a/src/app/core/entity/database-field.decorator.spec.ts b/src/app/core/entity/database-field.decorator.spec.ts index ef979efe61..6a11fb77f1 100644 --- a/src/app/core/entity/database-field.decorator.spec.ts +++ b/src/app/core/entity/database-field.decorator.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { DatabaseField } from "./database-field.decorator"; class TestClass extends Entity { diff --git a/src/app/core/entity/database-indexing/database-indexing.service.ts b/src/app/core/entity/database-indexing/database-indexing.service.ts index 6404b865ce..9b85201204 100644 --- a/src/app/core/entity/database-indexing/database-indexing.service.ts +++ b/src/app/core/entity/database-indexing/database-indexing.service.ts @@ -19,7 +19,7 @@ import { Injectable } from "@angular/core"; import { Database, QueryOptions } from "../../database/database"; import { BehaviorSubject, Observable } from "rxjs"; import { BackgroundProcessState } from "../../sync-status/background-process-state.interface"; -import { Entity, EntityConstructor } from "../entity"; +import { Entity, EntityConstructor } from "../model/entity"; import { EntitySchemaService } from "../schema/entity-schema.service"; import { first } from "rxjs/operators"; diff --git a/src/app/core/entity/entity-config.service.spec.ts b/src/app/core/entity/entity-config.service.spec.ts index 56f341baed..a2012c1e1e 100644 --- a/src/app/core/entity/entity-config.service.spec.ts +++ b/src/app/core/entity/entity-config.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed } from "@angular/core/testing"; import { EntityConfig, EntityConfigService } from "./entity-config.service"; import { DatabaseEntity } from "./database-entity.decorator"; import { DatabaseField } from "./database-field.decorator"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { ConfigService } from "../config/config.service"; describe("EntityConfigService", () => { diff --git a/src/app/core/entity/entity-config.service.ts b/src/app/core/entity/entity-config.service.ts index 8b0f44a6e3..1c44fd0863 100644 --- a/src/app/core/entity/entity-config.service.ts +++ b/src/app/core/entity/entity-config.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { ConfigService } from "../config/config.service"; import { EntitySchemaField } from "./schema/entity-schema-field"; import { addPropertySchema } from "./database-field.decorator"; diff --git a/src/app/core/entity/entity-mapper.service.spec.ts b/src/app/core/entity/entity-mapper.service.spec.ts index 160ce39b51..e33f9573fb 100644 --- a/src/app/core/entity/entity-mapper.service.spec.ts +++ b/src/app/core/entity/entity-mapper.service.spec.ts @@ -16,7 +16,7 @@ */ import { EntityMapperService } from "./entity-mapper.service"; -import { Entity } from "./entity"; +import { Entity } from "./model/entity"; import { EntitySchemaService } from "./schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; import { PouchDatabase } from "../database/pouch-database"; diff --git a/src/app/core/entity/entity-mapper.service.ts b/src/app/core/entity/entity-mapper.service.ts index 428044e3ba..c9cc4248da 100644 --- a/src/app/core/entity/entity-mapper.service.ts +++ b/src/app/core/entity/entity-mapper.service.ts @@ -17,10 +17,10 @@ import { Injectable } from "@angular/core"; import { Database } from "../database/database"; -import { Entity, EntityConstructor } from "./entity"; +import { Entity, EntityConstructor } from "./model/entity"; import { EntitySchemaService } from "./schema/entity-schema.service"; import { Observable, Subject } from "rxjs"; -import { UpdatedEntity } from "./entity-update"; +import { UpdatedEntity } from "./model/entity-update"; /** * Handles loading and saving of data for any higher-level feature module. diff --git a/src/app/core/entity/mock-entity-mapper-service.ts b/src/app/core/entity/mock-entity-mapper-service.ts index 6200fbecaa..a39ff937fd 100644 --- a/src/app/core/entity/mock-entity-mapper-service.ts +++ b/src/app/core/entity/mock-entity-mapper-service.ts @@ -1,6 +1,6 @@ -import { Entity, EntityConstructor } from "./entity"; +import { Entity, EntityConstructor } from "./model/entity"; import { EntityMapperService } from "./entity-mapper.service"; -import { UpdatedEntity } from "./entity-update"; +import { UpdatedEntity } from "./model/entity-update"; import { NEVER, Observable } from "rxjs"; export function mockEntityMapper( diff --git a/src/app/core/entity/entity-update.spec.ts b/src/app/core/entity/model/entity-update.spec.ts similarity index 100% rename from src/app/core/entity/entity-update.spec.ts rename to src/app/core/entity/model/entity-update.spec.ts diff --git a/src/app/core/entity/entity-update.ts b/src/app/core/entity/model/entity-update.ts similarity index 100% rename from src/app/core/entity/entity-update.ts rename to src/app/core/entity/model/entity-update.ts diff --git a/src/app/core/entity/entity.spec.ts b/src/app/core/entity/model/entity.spec.ts similarity index 96% rename from src/app/core/entity/entity.spec.ts rename to src/app/core/entity/model/entity.spec.ts index 2eb1bbaa8d..afd1bf6c67 100644 --- a/src/app/core/entity/entity.spec.ts +++ b/src/app/core/entity/model/entity.spec.ts @@ -17,8 +17,8 @@ import { Entity } from "./entity"; import { waitForAsync } from "@angular/core/testing"; -import { EntitySchemaService } from "./schema/entity-schema.service"; -import { DatabaseField } from "./database-field.decorator"; +import { EntitySchemaService } from "../schema/entity-schema.service"; +import { DatabaseField } from "../database-field.decorator"; describe("Entity", () => { let entitySchemaService: EntitySchemaService; diff --git a/src/app/core/entity/entity.ts b/src/app/core/entity/model/entity.ts similarity index 94% rename from src/app/core/entity/entity.ts rename to src/app/core/entity/model/entity.ts index 2c85d0a8d8..6a7c10cc4b 100644 --- a/src/app/core/entity/entity.ts +++ b/src/app/core/entity/model/entity.ts @@ -16,13 +16,9 @@ */ import { v4 as uuid } from "uuid"; -import { EntitySchema } from "./schema/entity-schema"; -import { DatabaseField } from "./database-field.decorator"; -import { - WarningLevel, - WarningLevelColor, -} from "../../child-dev-project/warning-level"; -import { FormGroup } from "@angular/forms"; +import { EntitySchema } from "../schema/entity-schema"; +import { DatabaseField } from "../database-field.decorator"; +import { getWarningLevelColor, WarningLevel } from "./warning-level"; /** * This represents a static class of type . @@ -95,10 +91,6 @@ export class Entity { } } - static validateForm(formGroup: FormGroup) { - return; - } - static getBlockComponent(): string { return; } @@ -210,8 +202,8 @@ export class Entity { * Used by some generic UI components to set the color for the entity instance. * Override this method as needed. */ - public getColor() { - return WarningLevelColor(this.getWarningLevel()); + public getColor(): string { + return getWarningLevelColor(this.getWarningLevel()); } /** @@ -232,4 +224,11 @@ export class Entity { Object.assign(other, this); return other; } + + /** + * Checks if the entity is valid and if the check fails, throws an error explaining the failed check. + */ + assertValid(): void { + return; + } } diff --git a/src/app/child-dev-project/warning-level.ts b/src/app/core/entity/model/warning-level.ts similarity index 81% rename from src/app/child-dev-project/warning-level.ts rename to src/app/core/entity/model/warning-level.ts index 60a1a0d30f..c90c3d9569 100644 --- a/src/app/child-dev-project/warning-level.ts +++ b/src/app/core/entity/model/warning-level.ts @@ -1,18 +1,18 @@ export enum WarningLevel { - OK = "OK", WARNING = "WARNING", URGENT = "URGENT", + OK = "OK", NONE = "", } -export function WarningLevelColor(warningLevel: WarningLevel): string { +export function getWarningLevelColor(warningLevel: WarningLevel) { switch (warningLevel) { - case WarningLevel.OK: - return "#90ee9040"; case WarningLevel.WARNING: return "#ffa50080"; case WarningLevel.URGENT: return "#fd727280"; + case WarningLevel.OK: + return "#90ee9040"; default: return ""; } diff --git a/src/app/core/entity/schema-datatypes/datatype-boolean.ts b/src/app/core/entity/schema-datatypes/datatype-boolean.ts new file mode 100644 index 0000000000..8f5227513a --- /dev/null +++ b/src/app/core/entity/schema-datatypes/datatype-boolean.ts @@ -0,0 +1,11 @@ +import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; + +export const booleanEntitySchemaDatatype: EntitySchemaDatatype = { + name: "boolean", + editComponent: "EditBoolean", + viewComponent: "DisplayCheckmark", + + transformToDatabaseFormat: (value: boolean) => value, + + transformToObjectFormat: (value) => value, +}; diff --git a/src/app/core/entity/schema-datatypes/datatype-map.spec.ts b/src/app/core/entity/schema-datatypes/datatype-map.spec.ts index 55ddad4702..00b4cd4e58 100644 --- a/src/app/core/entity/schema-datatypes/datatype-map.spec.ts +++ b/src/app/core/entity/schema-datatypes/datatype-map.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { waitForAsync } from "@angular/core/testing"; import { DatabaseField } from "../database-field.decorator"; import { EntitySchemaService } from "../schema/entity-schema.service"; diff --git a/src/app/core/entity/schema-datatypes/datatype-number.ts b/src/app/core/entity/schema-datatypes/datatype-number.ts index 5fe9746861..33a5b6f196 100644 --- a/src/app/core/entity/schema-datatypes/datatype-number.ts +++ b/src/app/core/entity/schema-datatypes/datatype-number.ts @@ -32,7 +32,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; export const numberEntitySchemaDatatype: EntitySchemaDatatype = { name: "number", viewComponent: "DisplayText", - editComponent: "EditText", + editComponent: "EditNumber", transformToDatabaseFormat: (value) => { return Number(value); diff --git a/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts b/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts index 0ba7d41612..499aa39df1 100644 --- a/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts +++ b/src/app/core/entity/schema-datatypes/datatype-schema-embed.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { DatabaseField } from "../database-field.decorator"; import { EntitySchemaService } from "../schema/entity-schema.service"; import { waitForAsync } from "@angular/core/testing"; diff --git a/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts b/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts index ca5c9d0519..b00682c4d3 100644 --- a/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts +++ b/src/app/core/entity/schema-datatypes/datatype-schema-embed.ts @@ -18,7 +18,7 @@ import { EntitySchemaDatatype } from "../schema/entity-schema-datatype"; import { EntitySchemaField } from "../schema/entity-schema-field"; import { EntitySchemaService } from "../schema/entity-schema.service"; -import { EntityConstructor } from "../entity"; +import { EntityConstructor } from "../model/entity"; /** * Datatype for the EntitySchemaService transforming values of complex objects recursively. diff --git a/src/app/core/entity/schema/entity-schema-datatype.ts b/src/app/core/entity/schema/entity-schema-datatype.ts index a7a2e0cdfb..bd00573115 100644 --- a/src/app/core/entity/schema/entity-schema-datatype.ts +++ b/src/app/core/entity/schema/entity-schema-datatype.ts @@ -17,7 +17,7 @@ import { EntitySchemaField } from "./entity-schema-field"; import { EntitySchemaService } from "./entity-schema.service"; -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; /** * Interface to be implemented by any Datatype transformer of the Schema system. diff --git a/src/app/core/entity/schema/entity-schema-field.ts b/src/app/core/entity/schema/entity-schema-field.ts index 8d6fc0cb74..55eea9c2ea 100644 --- a/src/app/core/entity/schema/entity-schema-field.ts +++ b/src/app/core/entity/schema/entity-schema-field.ts @@ -67,6 +67,12 @@ export interface EntitySchemaField { */ viewComponent?: string; + /** + * (Optional) Define using which component this property should be editable in lists and forms. + * + * The name has to match one of the strings in the DYNAMIC_COMPONENT_MAP. + * If nothing is defined, the default component for this datatype will be used. + */ editComponent?: string; /** @@ -74,9 +80,19 @@ export interface EntitySchemaField { */ label?: string; + /** + * A short label which can be used in tables. + * If nothing is specified, the long name will be used. + */ labelShort?: string; + /** + * A further description of the property which can be displayed in tooltips. + */ description?: string; + /** + * If set to true, the entity cannot be saved without setting a value for this property. + */ required?: boolean; } diff --git a/src/app/core/entity/schema/entity-schema.service.spec.ts b/src/app/core/entity/schema/entity-schema.service.spec.ts index 09c14a2f52..d994b21aa7 100644 --- a/src/app/core/entity/schema/entity-schema.service.spec.ts +++ b/src/app/core/entity/schema/entity-schema.service.spec.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { waitForAsync } from "@angular/core/testing"; import { EntitySchemaService } from "./entity-schema.service"; import { DatabaseField } from "../database-field.decorator"; diff --git a/src/app/core/entity/schema/entity-schema.service.ts b/src/app/core/entity/schema/entity-schema.service.ts index 6d790db117..17db13b74f 100644 --- a/src/app/core/entity/schema/entity-schema.service.ts +++ b/src/app/core/entity/schema/entity-schema.service.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity"; +import { Entity } from "../model/entity"; import { EntitySchemaDatatype } from "./entity-schema-datatype"; import { Injectable } from "@angular/core"; import { defaultEntitySchemaDatatype } from "../schema-datatypes/datatype-default"; @@ -29,6 +29,7 @@ import { arrayEntitySchemaDatatype } from "../schema-datatypes/datatype-array"; import { schemaEmbedEntitySchemaDatatype } from "../schema-datatypes/datatype-schema-embed"; import { dateOnlyEntitySchemaDatatype } from "../schema-datatypes/datatype-date-only"; import { mapEntitySchemaDatatype } from "../schema-datatypes/datatype-map"; +import { booleanEntitySchemaDatatype } from "../schema-datatypes/datatype-boolean"; /** * Transform between entity instances and database objects @@ -63,6 +64,7 @@ export class EntitySchemaService { this.registerSchemaDatatype(arrayEntitySchemaDatatype); this.registerSchemaDatatype(schemaEmbedEntitySchemaDatatype); this.registerSchemaDatatype(mapEntitySchemaDatatype); + this.registerSchemaDatatype(booleanEntitySchemaDatatype); } /** diff --git a/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts b/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts index c784494ffb..8494f93c7d 100644 --- a/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts +++ b/src/app/core/form-dialog/form-dialog-wrapper/form-dialog-wrapper.component.ts @@ -7,7 +7,7 @@ import { Output, } from "@angular/core"; import { EntityMapperService } from "../../entity/entity-mapper.service"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { MatDialogRef } from "@angular/material/dialog"; /** diff --git a/src/app/core/form-dialog/form-dialog.service.spec.ts b/src/app/core/form-dialog/form-dialog.service.spec.ts index 0fb836a852..cb545e8296 100644 --- a/src/app/core/form-dialog/form-dialog.service.spec.ts +++ b/src/app/core/form-dialog/form-dialog.service.spec.ts @@ -3,7 +3,7 @@ import { MatDialogModule } from "@angular/material/dialog"; import { FormDialogService } from "./form-dialog.service"; import { Component, EventEmitter, Input } from "@angular/core"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { ShowsEntity } from "./shows-entity.interface"; import { FormDialogModule } from "./form-dialog.module"; import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; diff --git a/src/app/core/form-dialog/form-dialog.service.ts b/src/app/core/form-dialog/form-dialog.service.ts index d7769c7abf..fba888075c 100644 --- a/src/app/core/form-dialog/form-dialog.service.ts +++ b/src/app/core/form-dialog/form-dialog.service.ts @@ -5,7 +5,7 @@ import { ConfirmationDialogService } from "../confirmation-dialog/confirmation-d import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; import { ShowsEntity } from "./shows-entity.interface"; import { OnInitDynamicComponent } from "../view/dynamic-components/on-init-dynamic-component.interface"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Inject this service instead of MatDialog to display a form or details view as a modal diff --git a/src/app/core/form-dialog/shows-entity.interface.ts b/src/app/core/form-dialog/shows-entity.interface.ts index 18f5a393c8..6952c05522 100644 --- a/src/app/core/form-dialog/shows-entity.interface.ts +++ b/src/app/core/form-dialog/shows-entity.interface.ts @@ -1,5 +1,5 @@ import { FormDialogWrapperComponent } from "./form-dialog-wrapper/form-dialog-wrapper.component"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; /** * Interface to be implemented by Components so that they can be used with {@link FormDialogService}. diff --git a/src/app/core/latest-changes/changelog/changelog.component.spec.ts b/src/app/core/latest-changes/changelog/changelog.component.spec.ts index 52d1425c1a..f9c7a217a7 100644 --- a/src/app/core/latest-changes/changelog/changelog.component.spec.ts +++ b/src/app/core/latest-changes/changelog/changelog.component.spec.ts @@ -25,6 +25,7 @@ import { of } from "rxjs"; import { LatestChangesModule } from "../latest-changes.module"; import { SwUpdate } from "@angular/service-worker"; import { MarkdownModule } from "ngx-markdown"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; describe("ChangelogComponent", () => { let component: ChangelogComponent; @@ -42,10 +43,15 @@ describe("ChangelogComponent", () => { waitForAsync(() => { mockLatestChangesService = jasmine.createSpyObj([ "getChangelogsBeforeVersion", + "getChangelogsBetweenVersions", ]); TestBed.configureTestingModule({ - imports: [LatestChangesModule, MarkdownModule.forRoot()], + imports: [ + LatestChangesModule, + MarkdownModule.forRoot(), + NoopAnimationsModule, + ], providers: [ { provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: of([testChangelog]) }, diff --git a/src/app/core/permissions/disable-entity-operation.directive.spec.ts b/src/app/core/permissions/disable-entity-operation.directive.spec.ts index c65cc9be3c..6aa6a89941 100644 --- a/src/app/core/permissions/disable-entity-operation.directive.spec.ts +++ b/src/app/core/permissions/disable-entity-operation.directive.spec.ts @@ -5,7 +5,7 @@ import { } from "./entity-permissions.service"; import { Component, ElementRef, ViewChild } from "@angular/core"; import { fakeAsync, TestBed, tick } from "@angular/core/testing"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { MatTooltipModule } from "@angular/material/tooltip"; describe("DisableEntityOperationDirective", () => { diff --git a/src/app/core/permissions/disable-entity-operation.directive.ts b/src/app/core/permissions/disable-entity-operation.directive.ts index a8c3527b62..bee1764ce5 100644 --- a/src/app/core/permissions/disable-entity-operation.directive.ts +++ b/src/app/core/permissions/disable-entity-operation.directive.ts @@ -11,7 +11,7 @@ import { EntityPermissionsService, OperationType, } from "./entity-permissions.service"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DisabledWrapperComponent } from "./disabled-wrapper/disabled-wrapper.component"; /** diff --git a/src/app/core/permissions/entity-permissions.service.spec.ts b/src/app/core/permissions/entity-permissions.service.spec.ts index 944436e410..6c7eebbfe7 100644 --- a/src/app/core/permissions/entity-permissions.service.spec.ts +++ b/src/app/core/permissions/entity-permissions.service.spec.ts @@ -6,7 +6,7 @@ import { } from "./entity-permissions.service"; import { SessionService } from "../session/session-service/session.service"; import { User } from "../user/user"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { EntityConfigService } from "../entity/entity-config.service"; describe("EntityPermissionsService", () => { diff --git a/src/app/core/permissions/entity-permissions.service.ts b/src/app/core/permissions/entity-permissions.service.ts index 1053a56f8f..f13e914a0b 100644 --- a/src/app/core/permissions/entity-permissions.service.ts +++ b/src/app/core/permissions/entity-permissions.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { SessionService } from "../session/session-service/session.service"; import { EntityConfigService } from "../entity/entity-config.service"; diff --git a/src/app/core/ui/search/search.component.ts b/src/app/core/ui/search/search.component.ts index d1756d6709..f1fc3d7bd3 100644 --- a/src/app/core/ui/search/search.component.ts +++ b/src/app/core/ui/search/search.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { Child } from "../../../child-dev-project/children/model/child"; import { School } from "../../../child-dev-project/schools/model/school"; -import { Entity } from "../../entity/entity"; +import { Entity } from "../../entity/model/entity"; import { EntitySchemaService } from "../../entity/schema/entity-schema.service"; import { Subject } from "rxjs"; import { debounceTime, switchMap } from "rxjs/operators"; diff --git a/src/app/core/user/user.spec.ts b/src/app/core/user/user.spec.ts index 3c76a1bf63..731aee6c5b 100644 --- a/src/app/core/user/user.spec.ts +++ b/src/app/core/user/user.spec.ts @@ -17,7 +17,7 @@ import { User } from "./user"; import { waitForAsync } from "@angular/core/testing"; -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { EntitySchemaService } from "../entity/schema/entity-schema.service"; describe("User", () => { diff --git a/src/app/core/user/user.ts b/src/app/core/user/user.ts index 1949e1cd4a..b573454cba 100644 --- a/src/app/core/user/user.ts +++ b/src/app/core/user/user.ts @@ -15,7 +15,7 @@ * along with ndb-core. If not, see . */ -import { Entity } from "../entity/entity"; +import { Entity } from "../entity/model/entity"; import { DatabaseEntity } from "../entity/database-entity.decorator"; import { DatabaseField } from "../entity/database-field.decorator"; diff --git a/src/app/core/view/dynamic-components-map.ts b/src/app/core/view/dynamic-components-map.ts index c6b9781667..d6070cfcda 100644 --- a/src/app/core/view/dynamic-components-map.ts +++ b/src/app/core/view/dynamic-components-map.ts @@ -15,7 +15,7 @@ import { ChildBlockComponent } from "../../child-dev-project/children/child-bloc import { DisplayTextComponent } from "../entity-components/entity-utils/view-components/display-text/display-text.component"; import { DisplayCheckmarkComponent } from "../entity-components/entity-utils/view-components/display-checkmark/display-checkmark.component"; import { DisplayDateComponent } from "../entity-components/entity-utils/view-components/display-date/display-date.component"; -import { DisplayConfigurableEnumComponent } from "../entity-components/entity-utils/view-components/display-configurable-enum/display-configurable-enum.component"; +import { DisplayConfigurableEnumComponent } from "../configurable-enum/display-configurable-enum/display-configurable-enum.component"; import { ActivityAttendanceSectionComponent } from "../../child-dev-project/attendance/activity-attendance-section/activity-attendance-section.component"; import { BmiBlockComponent } from "../../child-dev-project/children/children-list/bmi-block/bmi-block.component"; import { ChildrenBmiDashboardComponent } from "../../child-dev-project/children/children-bmi-dashboard/children-bmi-dashboard.component"; @@ -23,9 +23,8 @@ import { DashboardShortcutWidgetComponent } from "../dashboard-shortcut-widget/d import { UserListComponent } from "../admin/user-list/user-list.component"; import { HistoricalDataComponent } from "../../features/historical-data/historical-data/historical-data.component"; import { EditTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-text/edit-text.component"; -import { EditConfigurableEnumComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-configurable-enum/edit-configurable-enum.component"; +import { EditConfigurableEnumComponent } from "../configurable-enum/edit-configurable-enum/edit-configurable-enum.component"; import { EditDateComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-date/edit-date.component"; -import { EditSelectableComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-selectable/edit-selectable.component"; import { EditAgeComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-age/edit-age.component"; import { EditBooleanComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-boolean/edit-boolean.component"; import { EditLongTextComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-long-text/edit-long-text.component"; @@ -40,6 +39,7 @@ import { EditPercentageComponent } from "../entity-components/entity-utils/dynam import { DisplayPercentageComponent } from "../entity-components/entity-utils/view-components/display-percentage/display-percentage.component"; import { DisplayUnitComponent } from "../entity-components/entity-utils/view-components/display-unit/display-unit.component"; import { FormComponent } from "../entity-components/entity-details/form/form.component"; +import { EditNumberComponent } from "../entity-components/entity-utils/dynamic-form-components/edit-number/edit-number.component"; export const DYNAMIC_COMPONENTS_MAP = new Map([ ["ChildrenCountDashboard", ChildrenCountDashboardComponent], @@ -71,7 +71,6 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditText", EditTextComponent], ["EditConfigurableEnum", EditConfigurableEnumComponent], ["EditDate", EditDateComponent], - ["EditSelectable", EditSelectableComponent], ["EditEntityArray", EditEntityArrayComponent], ["EditAge", EditAgeComponent], ["EditBoolean", EditBooleanComponent], @@ -84,4 +83,5 @@ export const DYNAMIC_COMPONENTS_MAP = new Map([ ["EditPercentage", EditPercentageComponent], ["DisplayPercentage", DisplayPercentageComponent], ["DisplayUnit", DisplayUnitComponent], + ["EditNumber", EditNumberComponent], ]); diff --git a/src/app/features/historical-data/demo-historical-data-generator.ts b/src/app/features/historical-data/demo-historical-data-generator.ts index ce1c789f87..0e24a28018 100644 --- a/src/app/features/historical-data/demo-historical-data-generator.ts +++ b/src/app/features/historical-data/demo-historical-data-generator.ts @@ -8,7 +8,7 @@ import { ConfigurableEnumConfig, } from "../../core/configurable-enum/configurable-enum.interface"; import { faker } from "../../core/demo-data/faker"; -import { ENTITY_CONFIG_PREFIX } from "../../core/entity/entity"; +import { ENTITY_CONFIG_PREFIX } from "../../core/entity/model/entity"; export class DemoHistoricalDataConfig { minCountAttributes: number; diff --git a/src/app/features/historical-data/historical-data.service.spec.ts b/src/app/features/historical-data/historical-data.service.spec.ts index 3ea26bfb57..e847b8347b 100644 --- a/src/app/features/historical-data/historical-data.service.spec.ts +++ b/src/app/features/historical-data/historical-data.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from "@angular/core/testing"; import { HistoricalDataService } from "./historical-data.service"; import { EntityMapperService } from "../../core/entity/entity-mapper.service"; -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { HistoricalEntityData } from "./historical-entity-data"; import { expectEntitiesToMatch } from "../../utils/expect-entity-data.spec"; import { PouchDatabase } from "../../core/database/pouch-database"; diff --git a/src/app/features/historical-data/historical-data/historical-data.component.spec.ts b/src/app/features/historical-data/historical-data/historical-data.component.spec.ts index 0baed6c436..36f7ad3b3f 100644 --- a/src/app/features/historical-data/historical-data/historical-data.component.spec.ts +++ b/src/app/features/historical-data/historical-data/historical-data.component.spec.ts @@ -8,7 +8,7 @@ import { import { HistoricalDataComponent } from "./historical-data.component"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { HistoricalDataModule } from "../historical-data.module"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HistoricalEntityData } from "../historical-entity-data"; import moment from "moment"; import { DatePipe } from "@angular/common"; diff --git a/src/app/features/historical-data/historical-data/historical-data.component.ts b/src/app/features/historical-data/historical-data/historical-data.component.ts index 6352c7da2c..83321a80b0 100644 --- a/src/app/features/historical-data/historical-data/historical-data.component.ts +++ b/src/app/features/historical-data/historical-data/historical-data.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { OnInitDynamicComponent } from "../../../core/view/dynamic-components/on-init-dynamic-component.interface"; import { HistoricalEntityData } from "../historical-entity-data"; import { PanelConfig } from "../../../core/entity-components/entity-details/EntityDetailsConfig"; -import { Entity } from "../../../core/entity/entity"; +import { Entity } from "../../../core/entity/model/entity"; import { HistoricalDataService } from "../historical-data.service"; import { FormFieldConfig } from "../../../core/entity-components/entity-form/entity-form/FormConfig"; diff --git a/src/app/features/historical-data/historical-entity-data.ts b/src/app/features/historical-data/historical-entity-data.ts index 65fd8e1e3c..2480f8d1c7 100644 --- a/src/app/features/historical-data/historical-entity-data.ts +++ b/src/app/features/historical-data/historical-entity-data.ts @@ -1,4 +1,4 @@ -import { Entity } from "../../core/entity/entity"; +import { Entity } from "../../core/entity/model/entity"; import { DatabaseEntity } from "../../core/entity/database-entity.decorator"; import { DatabaseField } from "../../core/entity/database-field.decorator"; diff --git a/src/app/features/reporting/query.service.spec.ts b/src/app/features/reporting/query.service.spec.ts index bb4fb4ccd9..82b393251c 100644 --- a/src/app/features/reporting/query.service.spec.ts +++ b/src/app/features/reporting/query.service.spec.ts @@ -2,7 +2,6 @@ import { TestBed } from "@angular/core/testing"; import { QueryService } from "./query.service"; import { Child } from "../../child-dev-project/children/model/child"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { EntityMapperService } from "../../core/entity/entity-mapper.service"; import { School } from "../../child-dev-project/schools/model/school"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; @@ -20,6 +19,7 @@ import { expectEntitiesToMatch } from "../../utils/expect-entity-data.spec"; import { Database } from "../../core/database/database"; import { ConfigurableEnumModule } from "../../core/configurable-enum/configurable-enum.module"; import { Note } from "../../child-dev-project/notes/model/note"; +import { genders } from "../../child-dev-project/children/model/genders"; describe("QueryService", () => { let service: QueryService; @@ -66,19 +66,19 @@ describe("QueryService", () => { beforeEach(async () => { const entityMapper = TestBed.inject(EntityMapperService); maleChristianChild = new Child("maleChristianChild"); - maleChristianChild.gender = Gender.MALE; + maleChristianChild.gender = genders[1]; maleChristianChild.religion = "christian"; await entityMapper.save(maleChristianChild); femaleChristianChild = new Child("femaleChristianChild"); - femaleChristianChild.gender = Gender.FEMALE; + femaleChristianChild.gender = genders[2]; femaleChristianChild.religion = "christian"; await entityMapper.save(femaleChristianChild); femaleMuslimChild = new Child("femaleMuslimChild"); - femaleMuslimChild.gender = Gender.FEMALE; + femaleMuslimChild.gender = genders[2]; femaleMuslimChild.religion = "muslim"; await entityMapper.save(femaleMuslimChild); maleChild = new Child("maleChild"); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; await entityMapper.save(maleChild); privateSchool = new School("privateSchool"); @@ -221,11 +221,11 @@ describe("QueryService", () => { }); it("should return all children with specified attributes", async () => { - const maleChristianQuery = `${Child.ENTITY_TYPE}:toArray[*gender=M & religion=christian]`; + const maleChristianQuery = `${Child.ENTITY_TYPE}:toArray:filterByObjectAttribute(gender, id, M)[*religion=christian]`; const maleChristians = await service.queryData(maleChristianQuery); expectEntitiesToMatch(maleChristians, [maleChristianChild]); - const femaleQuery = `${Child.ENTITY_TYPE}:toArray[*gender=F]`; + const femaleQuery = `${Child.ENTITY_TYPE}:toArray:filterByObjectAttribute(gender, id, F)`; const females = await service.queryData(femaleQuery); expectEntitiesToMatch(females, [femaleChristianChild, femaleMuslimChild]); @@ -243,7 +243,7 @@ describe("QueryService", () => { ${School.ENTITY_TYPE}:toArray[*privateSchool=true] :getRelated(${ChildSchoolRelation.ENTITY_TYPE}, schoolId) [*isActive=true].childId:addPrefix(${Child.ENTITY_TYPE}):unique - :toEntities[*gender=${Gender.MALE}]`; + :toEntities:filterByObjectAttribute(gender, id, M)`; const maleChildrenOnPrivateSchools = await service.queryData( maleChildrenOnPrivateSchoolsQuery @@ -273,7 +273,7 @@ describe("QueryService", () => { maleChild, ]); - const maleChildrenCountQuery = `[*gender=${Gender.MALE}]:count`; + const maleChildrenCountQuery = `:filterByObjectAttribute(gender, id, M):count`; const maleChildrenCount = await service.queryData( maleChildrenCountQuery, null, @@ -291,7 +291,7 @@ describe("QueryService", () => { ); expect(christianCount).toBe(2); - const maleChristiansCountQuery = `[*gender=${Gender.MALE} & religion=christian]:count`; + const maleChristiansCountQuery = `:filterByObjectAttribute(gender, id, M)[*religion=christian]:count`; const maleChristiansCount = await service.queryData( maleChristiansCountQuery, null, @@ -334,7 +334,7 @@ describe("QueryService", () => { :getRelated(${RecurringActivity.ENTITY_TYPE}, linkedGroups) :getRelated(${EventNote.ENTITY_TYPE}, relatesTo) :getParticipantsWithAttendance(PRESENT):addPrefix(${Child.ENTITY_TYPE}):unique - :toEntities[*gender=${Gender.FEMALE}]`; + :toEntities:filterByObjectAttribute(gender, id, F)`; const femaleParticipantsInPrivateSchools = await service.queryData( femaleParticipantsPrivateSchoolQuery ); diff --git a/src/app/features/reporting/query.service.ts b/src/app/features/reporting/query.service.ts index 3907e74f7d..814c87e18c 100644 --- a/src/app/features/reporting/query.service.ts +++ b/src/app/features/reporting/query.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { Entity, EntityConstructor } from "../../core/entity/entity"; +import { Entity, EntityConstructor } from "../../core/entity/model/entity"; import { Child } from "../../child-dev-project/children/model/child"; import { School } from "../../child-dev-project/schools/model/school"; import { RecurringActivity } from "../../child-dev-project/attendance/model/recurring-activity"; diff --git a/src/app/features/reporting/reporting.service.spec.ts b/src/app/features/reporting/reporting.service.spec.ts index 2bf5d4875e..81f20ea596 100644 --- a/src/app/features/reporting/reporting.service.spec.ts +++ b/src/app/features/reporting/reporting.service.spec.ts @@ -7,8 +7,8 @@ import { EventNote } from "../../child-dev-project/attendance/model/event-note"; import moment from "moment"; import { School } from "../../child-dev-project/schools/model/school"; import { ChildSchoolRelation } from "../../child-dev-project/children/model/childSchoolRelation"; -import { Gender } from "../../child-dev-project/children/model/Gender"; import { centersUnique } from "../../child-dev-project/children/demo-data-generators/fixtures/centers"; +import { genders } from "../../child-dev-project/children/model/genders"; describe("ReportingService", () => { let service: ReportingService; @@ -160,9 +160,9 @@ describe("ReportingService", () => { it("should correctly parse groupBy results", async () => { const maleChild = new Child(); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; const femaleChild = new Child(); - femaleChild.gender = Gender.FEMALE; + femaleChild.gender = genders[2]; mockQueryService.queryData.and.resolveTo([ femaleChild, maleChild, @@ -184,7 +184,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 1, }, subRows: [], @@ -192,7 +192,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [], @@ -204,9 +204,9 @@ describe("ReportingService", () => { it("should run aggregations after a groupBy", async () => { const maleChild = new Child(); - maleChild.gender = Gender.MALE; + maleChild.gender = genders[1]; const femaleChild = new Child(); - femaleChild.gender = Gender.FEMALE; + femaleChild.gender = genders[2]; mockQueryService.queryData.and.resolveTo([ maleChild, femaleChild, @@ -239,14 +239,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [ { header: { label: "Total # of christians", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 3, }, subRows: [], @@ -256,14 +256,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 1, }, subRows: [ { header: { label: "Total # of christians", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 3, }, subRows: [], @@ -279,19 +279,19 @@ describe("ReportingService", () => { const alipore = centersUnique.find((c) => c.id === "alipore"); const barabazar = centersUnique.find((c) => c.id === "barabazar"); const maleChristianAlipore = new Child(); - maleChristianAlipore.gender = Gender.MALE; + maleChristianAlipore.gender = genders[1]; maleChristianAlipore.religion = "christian"; maleChristianAlipore.center = alipore; const maleMuslimAlipore = new Child(); - maleMuslimAlipore.gender = Gender.MALE; + maleMuslimAlipore.gender = genders[1]; maleMuslimAlipore.religion = "muslim"; maleMuslimAlipore.center = alipore; const femaleChristianBarabazar = new Child(); - femaleChristianBarabazar.gender = Gender.FEMALE; + femaleChristianBarabazar.gender = genders[2]; femaleChristianBarabazar.religion = "christian"; femaleChristianBarabazar.center = barabazar; const femaleChristianAlipore = new Child(); - femaleChristianAlipore.gender = Gender.FEMALE; + femaleChristianAlipore.gender = genders[2]; femaleChristianAlipore.religion = "christian"; femaleChristianAlipore.center = alipore; mockQueryService.queryData.and.resolveTo([ @@ -382,7 +382,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 2, }, subRows: [ @@ -390,7 +390,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "center", value: alipore }, ], result: 1, @@ -401,7 +401,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "center", value: barabazar }, ], result: 1, @@ -412,7 +412,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, ], result: 2, @@ -422,7 +422,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, { property: "center", value: alipore }, ], @@ -434,7 +434,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, { property: "center", value: barabazar }, ], @@ -449,7 +449,7 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 2, }, subRows: [ @@ -457,7 +457,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "center", value: alipore }, ], result: 2, @@ -468,7 +468,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, ], result: 1, @@ -478,7 +478,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, { property: "center", value: alipore }, ], @@ -492,7 +492,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, ], result: 1, @@ -502,7 +502,7 @@ describe("ReportingService", () => { header: { label: "Total # of children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, { property: "center", value: alipore }, ], @@ -521,13 +521,13 @@ describe("ReportingService", () => { it("should allow multiple groupBy's", async () => { const femaleMuslim = new Child(); - femaleMuslim.gender = Gender.FEMALE; + femaleMuslim.gender = genders[2]; femaleMuslim.religion = "muslim"; const femaleChristian = new Child(); - femaleChristian.gender = Gender.FEMALE; + femaleChristian.gender = genders[2]; femaleChristian.religion = "christian"; const maleMuslim = new Child(); - maleMuslim.gender = Gender.MALE; + maleMuslim.gender = genders[1]; maleMuslim.religion = "muslim"; mockQueryService.queryData.and.resolveTo([ femaleChristian, @@ -584,14 +584,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 4, }, subRows: [ { header: { label: "Total # of old children", - groupedBy: [{ property: "gender", value: Gender.FEMALE }], + groupedBy: [{ property: "gender", value: genders[2] }], result: 5, }, subRows: [ @@ -599,7 +599,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "christian" }, ], result: 2, @@ -610,7 +610,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.FEMALE }, + { property: "gender", value: genders[2] }, { property: "religion", value: "muslim" }, ], result: 3, @@ -624,14 +624,14 @@ describe("ReportingService", () => { { header: { label: "Total # of children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 1, }, subRows: [ { header: { label: "Total # of old children", - groupedBy: [{ property: "gender", value: Gender.MALE }], + groupedBy: [{ property: "gender", value: genders[1] }], result: 5, }, subRows: [ @@ -639,7 +639,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "christian" }, ], result: 2, @@ -650,7 +650,7 @@ describe("ReportingService", () => { header: { label: "Total # of old children", groupedBy: [ - { property: "gender", value: Gender.MALE }, + { property: "gender", value: genders[1] }, { property: "religion", value: "muslim" }, ], result: 3, diff --git a/src/app/features/reporting/reporting/reporting.stories.ts b/src/app/features/reporting/reporting/reporting.stories.ts index 94d3d0941b..02e84417d0 100644 --- a/src/app/features/reporting/reporting/reporting.stories.ts +++ b/src/app/features/reporting/reporting/reporting.stories.ts @@ -9,11 +9,10 @@ import { MatNativeDateModule } from "@angular/material/core"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { FontAwesomeIconsModule } from "../../../core/icons/font-awesome-icons.module"; import { BackupService } from "../../../core/admin/services/backup.service"; -import { Gender } from "../../../child-dev-project/children/model/Gender"; import { ReportingModule } from "../reporting.module"; +import { genders } from "../../../child-dev-project/children/model/genders"; const reportingService = { - setAggregations: () => null, calculateReport: () => { return Promise.resolve([ { @@ -80,7 +79,7 @@ const reportingService = { { header: { label: "Total # of children", - values: [Gender.FEMALE], + values: [genders[2]], result: 2, }, subRows: [ @@ -130,7 +129,7 @@ const reportingService = { { header: { label: "Total # of children", - values: [Gender.MALE], + values: [genders[1]], result: 2, }, subRows: [ diff --git a/src/app/utils/expect-entity-data.spec.ts b/src/app/utils/expect-entity-data.spec.ts index 6d1ca14ef7..c00d4e921a 100644 --- a/src/app/utils/expect-entity-data.spec.ts +++ b/src/app/utils/expect-entity-data.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from "@angular/core/testing"; import { EntitySchemaService } from "../core/entity/schema/entity-schema.service"; -import { Entity } from "../core/entity/entity"; +import { Entity } from "../core/entity/model/entity"; import { EntityMapperService } from "../core/entity/entity-mapper.service"; /** From 8dbb469b93b83e8d25c84e874b94d6d221e375d2 Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Wed, 30 Jun 2021 17:41:02 +0200 Subject: [PATCH 214/230] simplify child fields for health --- .../educational-material/model/materials.ts | 4 +++ src/app/core/config/config-fix.ts | 30 ------------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/src/app/child-dev-project/educational-material/model/materials.ts b/src/app/child-dev-project/educational-material/model/materials.ts index 924559ac93..199a2d9fc3 100644 --- a/src/app/child-dev-project/educational-material/model/materials.ts +++ b/src/app/child-dev-project/educational-material/model/materials.ts @@ -1,6 +1,10 @@ import { ConfigurableEnumValue } from "../../../core/configurable-enum/configurable-enum.interface"; export const materials: ConfigurableEnumValue[] = [ + { + id: "OTHER", + label: "", + }, { id: "pencil", label: "pencil", diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 82d3ca7632..33a52f095b 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -432,13 +432,8 @@ export const defaultJsonConfig = { "name", "center", "health_BMI", - "health_vaccinationStatus", "health_bloodGroup", - "health_eyeHealthStatus", - "health_lastEyeCheckup", "health_lastDentalCheckup", - "health_lastENTCheckup", - "health_lastVitaminD", "health_lastDeworming", "gender", "age", @@ -573,13 +568,8 @@ export const defaultJsonConfig = { "component": "Form", "config": { "cols": [ - ["health_vaccinationStatus"], - ["health_eyeHealthStatus"], ["health_bloodGroup"], ["health_lastDentalCheckup"], - ["health_lastEyeCheckup"], - ["health_lastENTCheckup"], - ["health_lastVitaminD"], ["health_lastDeworming"] ] } @@ -801,10 +791,6 @@ export const defaultJsonConfig = { "name": "has_BplCard", "schema": { "dataType": "configurable-enum", "innerDataType": "document-status", label: "BPL Card" } }, - { - "name": "health_vaccinationStatus", - "schema": { "dataType": "string", label: "Vaccination Status", additional: ["", "Good", "Vaccination Due", "Needs Checking", "No Card/Information"] } - }, { "name": "health_bloodGroup", "schema": { "dataType": "string", label: "Blood Group" } @@ -813,22 +799,6 @@ export const defaultJsonConfig = { "name": "health_lastDentalCheckup", "schema": { "dataType": "Date", label: "Last Dental Check-Up" } }, - { - "name": "health_lastEyeCheckup", - "schema": { "dataType": "Date", label: "Last Eye Check-Up", additional: ["", "Good", "Has Glasses", "Needs Glasses", "Needs Checkup"] } - }, - { - "name": "health_lastENTCheckup", - "schema": { "dataType": "Date", label: "Last ENT Check-Up" } - }, - { - "name": "health_eyeHealthStatus", - "schema": { "dataType": "string", label: "Eye Status" } - }, - { - "name": "health_lastVitaminD", - "schema": { "dataType": "Date", label: "Last Vitamin D" } - }, { "name": "health_lastDeworming", "schema": { "dataType": "Date", label: "Last De-Worming" } From f74dd5e914012dcb697f4a1c057746948967ddb7 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 09:26:36 +0200 Subject: [PATCH 215/230] removing label and display text components --- .../config/config-migration.service.spec.ts | 18 -------- .../core/config/config-migration.service.ts | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index 8b779f0736..e101cf0166 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -348,7 +348,6 @@ const expectedChildrenListConfig = { columns: [ { view: "ChildBlock", - label: "Name", id: "name", }, { @@ -358,7 +357,6 @@ const expectedChildrenListConfig = { }, { view: "DisplayDate", - label: "DoB", id: "dateOfBirth", }, { @@ -369,7 +367,6 @@ const expectedChildrenListConfig = { noSorting: true, }, { - title: "Gender", id: "gender", }, { @@ -383,7 +380,6 @@ const expectedChildrenListConfig = { }, { view: "DisplayConfigurableEnum", - label: "Center", id: "center", }, { @@ -491,20 +487,17 @@ const expectedChildDetailsConfig = { { edit: "EditPhoto", id: "photo", - label: "Photo Filename", }, ], [ { edit: "EditText", id: "name", - label: "Name", required: true, }, { edit: "EditConfigurableEnum", id: "center", - label: "Center", additional: "center", }, ], @@ -514,22 +507,18 @@ const expectedChildDetailsConfig = { tooltip: "This field is read-only. Edit Date of Birth to change age. Select Jan 1st if you only know the year of birth.", id: "dateOfBirth", - label: "Date of Birth", }, { id: "gender", - label: "Gender", }, { id: "status", - label: "Status", }, ], [ { edit: "EditDate", id: "admissionDate", - label: "Admission Date", }, ], [ @@ -561,32 +550,26 @@ const expectedChildDetailsConfig = { columns: [ { id: "schoolId", - label: "School", view: "DisplayEntity", edit: "EditSingleEntity", additional: "School", }, { id: "schoolClass", - label: "Class", - view: "DisplayText", edit: "EditText", }, { id: "start", - label: "From", view: "DisplayDate", edit: "EditDate", }, { id: "end", - label: "To", view: "DisplayDate", edit: "EditDate", }, { id: "result", - label: "Result", view: "DisplayPercentage", edit: "EditPercentage", }, @@ -632,7 +615,6 @@ const expectedChildDetailsConfig = { config: [ { id: "date", - label: "Date", view: "DisplayDate", edit: "EditDate", }, diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 19e60545d8..10c0161c1c 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -37,13 +37,6 @@ import { warningLevels } from "../../child-dev-project/warning-levels"; providedIn: "root", }) export class ConfigMigrationService { - readonly entityListComponents = [ - "ChildrenList", - "SchoolsList", - "ActivityList", - "NotesManager", - ]; - private config: Config; constructor( private configService: ConfigService, @@ -73,10 +66,16 @@ export class ConfigMigrationService { } private migrateViewConfigs() { + const entityListComponents = [ + "ChildrenList", + "SchoolsList", + "ActivityList", + "NotesManager", + ]; const viewConfigs = this.configService.getAllConfigs("view:"); viewConfigs.forEach((viewConfig) => { const entity = this.getEntity(viewConfig._id); - if (this.entityListComponents.includes(viewConfig.component)) { + if (entityListComponents.includes(viewConfig.component)) { this.migrateEntityListConfig(viewConfig.config, entity); } if (viewConfig.component === "EntityDetails") { @@ -138,13 +137,7 @@ export class ConfigMigrationService { column.additional = "Child"; column.noSorting = true; } - const propertySchema = entity.schema.get(column.id); - if (propertySchema?.dataType === "configurable-enum") { - delete column.view; - delete column.edit; - delete column.additional; - } - this.addLabelToEntity(column.label, column.id, entity, "short"); + this.addLabelToEntity(column.label, column.id, entity, "short", column); } catch (e) { console.warn(`Failed to migrate column ${column.id}: ${e}`); } @@ -155,7 +148,8 @@ export class ConfigMigrationService { label: string, attribute: string, entity: EntityConstructor, - type: "short" | "long" + type: "short" | "long", + formField?: FormFieldConfig ) { try { const schema = entity.schema.get(attribute); @@ -182,6 +176,12 @@ export class ConfigMigrationService { configSchema.attributes.push(existing); } existing.schema = schema; + if (formField) { + delete formField.label; + if (formField.view === "DisplayText") { + delete formField.view; + } + } } catch (e) { console.warn( `Failed to set label ${label} to attribute ${attribute} of entity ${entity.ENTITY_TYPE}: ${e}` @@ -288,7 +288,13 @@ export class ConfigMigrationService { formField.edit = editMap.get(formField["input"]); } delete formField["input"]; - this.addLabelToEntity(formField.label, formField.id, entity, "short"); + this.addLabelToEntity( + formField.label, + formField.id, + entity, + "short", + formField + ); } catch (e) { console.warn(`Failed to migrate form field ${formField.id}: ${e}`); } @@ -342,7 +348,8 @@ export class ConfigMigrationService { formField.label, formField.id, ChildSchoolRelation, - "long" + "long", + formField ); } catch (e) { console.warn( @@ -438,7 +445,8 @@ export class ConfigMigrationService { formField.label, formField.id, HistoricalEntityData, - "long" + "long", + formField ); } catch (e) { console.warn( From 501b43079403a368d1e187e2764d45c023f1a66b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 09:41:38 +0200 Subject: [PATCH 216/230] updating input entity --- .../entity-form/entity-form.service.spec.ts | 7 ++++--- .../entity-components/entity-form/entity-form.service.ts | 2 +- .../entity-form/entity-form/entity-form.component.ts | 5 +---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts index fa807d40b6..0a157cb243 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.spec.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.spec.ts @@ -36,14 +36,15 @@ describe("EntityFormService", () => { const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); expect(() => service.saveChanges(formGroup, entity)).toThrowError(); + expect(entity.getId).not.toBe("newId"); }); - it("should return updated entity if saving is successful", async () => { + it("should update entity if saving is successful", async () => { const entity = new Entity("initialId"); const formGroup = TestBed.inject(FormBuilder).group({ _id: "newId" }); - const newEntity = await service.saveChanges(formGroup, entity); + await service.saveChanges(formGroup, entity); - expect(newEntity.getId()).toBe("newId"); + expect(entity.getId()).toBe("newId"); }); }); diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index e8f882c1a2..5e541d1fdc 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -87,7 +87,7 @@ export class EntityFormService { return this.entityMapper .save(entityCopy) - .then(() => entityCopy) + .then(() => Object.assign(entity, entityCopy)) .catch((err) => { throw new Error(`Could not save ${entity.getType()}: ${err}`); }); diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts index 1b8bd940ff..00fb078ee2 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.component.ts @@ -84,10 +84,7 @@ export class EntityFormComponent implements OnInit { async save(): Promise { try { - this.entity = await this.entityFormService.saveChanges( - this.form, - this.entity - ); + await this.entityFormService.saveChanges(this.form, this.entity); this.onSave.emit(this.entity); this.switchEdit(); } catch (err) { From f894c4b8fcaf7ca98a1dd60c2c01933c81f6af03 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 10:00:56 +0200 Subject: [PATCH 217/230] changed the saved lables --- src/app/core/config/config-migration.service.ts | 16 ++++++++-------- .../entity-form/entity-form.service.ts | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 10c0161c1c..a4b73428f0 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -292,7 +292,7 @@ export class ConfigMigrationService { formField.label, formField.id, entity, - "short", + "long", formField ); } catch (e) { @@ -348,7 +348,7 @@ export class ConfigMigrationService { formField.label, formField.id, ChildSchoolRelation, - "long", + "short", formField ); } catch (e) { @@ -386,9 +386,9 @@ export class ConfigMigrationService { }, ], } as any; - this.addLabelToEntity("Team", "schoolId", ChildSchoolRelation, "long"); - this.addLabelToEntity("From", "start", ChildSchoolRelation, "long"); - this.addLabelToEntity("To", "end", ChildSchoolRelation, "long"); + this.addLabelToEntity("Team", "schoolId", ChildSchoolRelation, "short"); + this.addLabelToEntity("From", "start", ChildSchoolRelation, "short"); + this.addLabelToEntity("To", "end", ChildSchoolRelation, "short"); } private migrateEntitySubrecordInput( @@ -445,7 +445,7 @@ export class ConfigMigrationService { formField.label, formField.id, HistoricalEntityData, - "long", + "short", formField ); } catch (e) { @@ -476,12 +476,12 @@ export class ConfigMigrationService { ], ], } as any; - this.addLabelToEntity("Groups", "linkedGroups", RecurringActivity, "long"); + this.addLabelToEntity("Groups", "linkedGroups", RecurringActivity, "short"); this.addLabelToEntity( "Participants", "participants", RecurringActivity, - "long" + "short" ); } diff --git a/src/app/core/entity-components/entity-form/entity-form.service.ts b/src/app/core/entity-components/entity-form/entity-form.service.ts index 5e541d1fdc..7280df72cc 100644 --- a/src/app/core/entity-components/entity-form/entity-form.service.ts +++ b/src/app/core/entity-components/entity-form/entity-form.service.ts @@ -48,7 +48,8 @@ export class EntityFormService { formField.label || propertySchema.labelShort || propertySchema.label; } else { formField.forTable = false; - formField.label = formField.label || propertySchema.label; + formField.label = + formField.label || propertySchema.label || propertySchema.labelShort; } } From aedd6c795010eedca0f30c9f8473b4134f994935 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 13:49:48 +0200 Subject: [PATCH 218/230] fixed assignedTo conversion --- .../config/config-migration.service.spec.ts | 90 ++++++++++++++++--- .../core/config/config-migration.service.ts | 9 ++ 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index e101cf0166..ae39f40097 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -4,13 +4,18 @@ import { ConfigMigrationService } from "./config-migration.service"; import { ConfigService } from "./config.service"; import { EntityMapperService } from "../entity/entity-mapper.service"; import { Config } from "./config"; -import { EntityConfig } from "../entity/entity-config.service"; +import { + EntityConfig, + EntityConfigService, +} from "../entity/entity-config.service"; import { CONFIGURABLE_ENUM_CONFIG_PREFIX, ConfigurableEnumValue, } from "../configurable-enum/configurable-enum.interface"; import { genders } from "../../child-dev-project/children/model/genders"; import { EntitySchemaField } from "../entity/schema/entity-schema-field"; +import { Child } from "../../child-dev-project/children/model/child"; +import { HistoricalEntityData } from "../../features/historical-data/historical-entity-data"; describe("ConfigMigrationService", () => { let service: ConfigMigrationService; @@ -186,11 +191,16 @@ describe("ConfigMigrationService", () => { placeholder: "Address", }, { - input: "entity-select", + input: "text", id: "assignedTo", - entityType: "User", - placeholder: "Add coordinator...", - label: "Assigned to", + placeholder: "Additional Information", + }, + { + input: "entity-select", + id: "children", + entityType: "Child", + placeholder: "Add children...", + label: "Assigned children", }, ], ], @@ -280,18 +290,60 @@ describe("ConfigMigrationService", () => { ], }, }, + "entity:Child": { + permissions: {}, + attributes: [ + { + name: "children", + schema: { dataType: "array", innerDataType: "string" }, + }, + { + name: "assignedTo", + schema: { dataType: "string" }, + }, + { + name: "address", + schema: { dataType: "string" }, + }, + ], + }, + "entity:HistoricalEntityData": { + permissions: {}, + attributes: [ + { + name: "observer", + schema: { + dataType: "string", + }, + }, + { + name: "isMotivatedDuringClass", + schema: { + dataType: "configurable-enum", + innerDataType: "rating-answer", + }, + }, + ], + }, }; mockEntityMapper = jasmine.createSpyObj(["load", "save"]); mockEntityMapper.load.and.resolveTo(config); mockEntityMapper.save.and.resolveTo(); TestBed.configureTestingModule({ providers: [ + EntityConfigService, ConfigService, { provide: EntityMapperService, useValue: mockEntityMapper }, ], }); service = TestBed.inject(ConfigMigrationService); configService = TestBed.inject(ConfigService); + + await configService.loadConfig(mockEntityMapper); + const entityConfigService = TestBed.inject(EntityConfigService); + entityConfigService.addConfigAttributes(Child); + entityConfigService.addConfigAttributes(HistoricalEntityData); + await service.migrateConfig(); }); @@ -331,6 +383,11 @@ describe("ConfigMigrationService", () => { CONFIGURABLE_ENUM_CONFIG_PREFIX + "status" ); expect(statusEnum).toEqual(expectedStatusConfigurableEnum); + + const assignedToSchema = childConfig.attributes.find( + (attr) => attr.name === "assignedTo" + ).schema; + expect(assignedToSchema).toEqual(expectedAssignedToSchema); }); it("should add configurable enum configs", () => { @@ -384,7 +441,6 @@ const expectedChildrenListConfig = { }, { view: "DisplayEntityArray", - label: "Children", id: "children", additional: "Child", noSorting: true, @@ -446,7 +502,15 @@ const expectedStatusSchema: EntitySchemaField = { dataType: "configurable-enum", innerDataType: "status", label: "Status", - labelShort: "Status", +}; + +const expectedAssignedToSchema: EntitySchemaField = { + dataType: "array", + innerDataType: "string", + editComponent: "EditEntityArray", + viewComponent: "DisplayEntityArray", + additional: "User", + label: "Assigned user(s)", }; const expectedStatusConfigurableEnum: ConfigurableEnumValue[] = [ @@ -525,13 +589,14 @@ const expectedChildDetailsConfig = { { edit: "EditLongText", id: "address", - label: "Address", }, { - edit: "EditEntityArray", id: "assignedTo", - additional: "User", - label: "Assigned to", + }, + { + edit: "EditEntityArray", + id: "children", + additional: "Child", }, ], ], @@ -620,7 +685,6 @@ const expectedChildDetailsConfig = { }, { id: "isMotivatedDuringClass", - label: "Motivated", view: "DisplayConfigurableEnum", edit: "EditConfigurableEnum", additional: "rating-answer", @@ -628,8 +692,6 @@ const expectedChildDetailsConfig = { }, { id: "observer", - label: "Observer", - view: "DisplayText", edit: "EditText", tooltip: "Name of the observer", }, diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index a4b73428f0..667dffb685 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -32,6 +32,7 @@ import { ConfigurableEnumValue, } from "../configurable-enum/configurable-enum.interface"; import { warningLevels } from "../../child-dev-project/warning-levels"; +import { User } from "../user/user"; @Injectable({ providedIn: "root", @@ -284,6 +285,14 @@ export class ConfigMigrationService { } if (formField["input"] === "select") { this.migrateSelectFormField(formField, entity); + } else if (formField.id === "assignedTo") { + const schema = entity.schema.get("assignedTo"); + formField.label = "Assigned user(s)"; + schema.dataType = "array"; + schema.innerDataType = "string"; + schema.viewComponent = "DisplayEntityArray"; + schema.editComponent = "EditEntityArray"; + schema.additional = User.ENTITY_TYPE; } else { formField.edit = editMap.get(formField["input"]); } From acb4a663f93f90307890688ce3ce7e93fa89618c Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 16:12:16 +0200 Subject: [PATCH 219/230] fixed bug where for configurable enum filters --- .../entity-list/filter-generator.service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index ffc733bb31..ca7e3420f3 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -98,7 +98,7 @@ export class FilterGeneratorService { filter: BooleanFilterConfig ): FilterSelectionOption[] { return [ - { key: "", label: filter.all, filterFun: () => true }, + { key: null, label: filter.all, filterFun: () => true }, { key: "true", label: filter.true, @@ -116,7 +116,7 @@ export class FilterGeneratorService { property: string, enumId: string ): FilterSelectionOption[] { - const options = [{ key: "", label: "All", filterFun: (e: T) => true }]; + const options = [{ key: null, label: "All", filterFun: (e: T) => true }]; const enumValues = this.configService.getConfig( CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId @@ -142,12 +142,12 @@ export class FilterGeneratorService { entityConstructor ); - const options = [{ key: "", label: "All", filterFun: (e: T) => true }]; + const options = [{ key: null, label: "All", filterFun: (e: T) => true }]; options.push( ...filterEntities.map((filterEntity) => { return { key: filterEntity.getId(), - label: filterEntity["name"] || filterEntity.getId(), + label: filterEntity.toString(), filterFun: (entity) => entity[property] === filterEntity.getId(), }; }) From 24e43537b135c5de130b413454c8033386438a4e Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 16:21:44 +0200 Subject: [PATCH 220/230] moved sorting accessor --- .../entity-subrecord/entity-subrecord.component.ts | 2 +- .../entity-subrecord}/sorting-accessor.spec.ts | 0 .../entity-subrecord}/sorting-accessor.ts | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/app/core/entity-components/{entity-list => entity-subrecord/entity-subrecord}/sorting-accessor.spec.ts (100%) rename src/app/core/entity-components/{entity-list => entity-subrecord/entity-subrecord}/sorting-accessor.ts (100%) diff --git a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts index 5cc91b59db..de1e6a9355 100644 --- a/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts +++ b/src/app/core/entity-components/entity-subrecord/entity-subrecord/entity-subrecord.component.ts @@ -15,7 +15,7 @@ import { Entity } from "../../../entity/model/entity"; import { ConfirmationDialogService } from "../../../confirmation-dialog/confirmation-dialog.service"; import { AlertService } from "../../../alerts/alert.service"; import { Subscription } from "rxjs"; -import { entityListSortingAccessor } from "../../entity-list/sorting-accessor"; +import { entityListSortingAccessor } from "./sorting-accessor"; import { FormGroup } from "@angular/forms"; import { FormFieldConfig } from "../../entity-form/entity-form/FormConfig"; import { EntityFormService } from "../../entity-form/entity-form.service"; diff --git a/src/app/core/entity-components/entity-list/sorting-accessor.spec.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/sorting-accessor.spec.ts similarity index 100% rename from src/app/core/entity-components/entity-list/sorting-accessor.spec.ts rename to src/app/core/entity-components/entity-subrecord/entity-subrecord/sorting-accessor.spec.ts diff --git a/src/app/core/entity-components/entity-list/sorting-accessor.ts b/src/app/core/entity-components/entity-subrecord/entity-subrecord/sorting-accessor.ts similarity index 100% rename from src/app/core/entity-components/entity-list/sorting-accessor.ts rename to src/app/core/entity-components/entity-subrecord/entity-subrecord/sorting-accessor.ts From bfdaf390fb44ec6832041f08e333381090915b72 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 16:39:24 +0200 Subject: [PATCH 221/230] fixed filtering accessor --- .../entity-list/entity-list.component.ts | 9 ++++++++- .../entity-list/filter-predicate.spec.ts | 15 +++++++++++++++ .../entity-list/filter-predicate.ts | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/app/core/entity-components/entity-list/filter-predicate.spec.ts create mode 100644 src/app/core/entity-components/entity-list/filter-predicate.ts diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 14453497a8..5f50395ed9 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -1,4 +1,5 @@ import { + AfterViewInit, Component, EventEmitter, Input, @@ -22,6 +23,7 @@ import { FormFieldConfig } from "../entity-form/entity-form/FormConfig"; import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/entity-subrecord.component"; import { FilterGeneratorService } from "./filter-generator.service"; import { FilterComponentSettings } from "./filter-component.settings"; +import { entityFilterPredicate } from "./filter-predicate"; /** * This component allows to create a full blown table with pagination, filtering, searching and grouping. @@ -36,7 +38,7 @@ import { FilterComponentSettings } from "./filter-component.settings"; styleUrls: ["./entity-list.component.scss"], }) export class EntityListComponent - implements OnChanges, OnInit { + implements OnChanges, OnInit, AfterViewInit { @Input() allEntities: T[] = []; filteredEntities: T[] = []; @Input() listConfig: EntityListConfig; @@ -84,6 +86,11 @@ export class EntityListComponent }); } + ngAfterViewInit() { + this.entityTable.recordsDataSource.filterPredicate = (data, filter) => + entityFilterPredicate(data.record, filter); + } + ngOnChanges(changes: SimpleChanges): void { if (changes.hasOwnProperty("listConfig")) { this.listName = this.listConfig.title; diff --git a/src/app/core/entity-components/entity-list/filter-predicate.spec.ts b/src/app/core/entity-components/entity-list/filter-predicate.spec.ts new file mode 100644 index 0000000000..9ceb54948c --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-predicate.spec.ts @@ -0,0 +1,15 @@ +import { Note } from "../../../child-dev-project/notes/model/note"; +import { defaultInteractionTypes } from "../../config/default-config/default-interaction-types"; +import { entityFilterPredicate } from "./filter-predicate"; + +describe("filterPredicate", () => { + it("should match configurable enum objects", () => { + const note = new Note(); + note.category = defaultInteractionTypes.find( + (it) => it.id === "HOME_VISIT" + ); + + const match = entityFilterPredicate(note, "home"); + expect(match).toBeTrue(); + }); +}); diff --git a/src/app/core/entity-components/entity-list/filter-predicate.ts b/src/app/core/entity-components/entity-list/filter-predicate.ts new file mode 100644 index 0000000000..50f5e54102 --- /dev/null +++ b/src/app/core/entity-components/entity-list/filter-predicate.ts @@ -0,0 +1,15 @@ +import { Entity } from "../../entity/model/entity"; +import { entityListSortingAccessor } from "../entity-subrecord/entity-subrecord/sorting-accessor"; + +export function entityFilterPredicate( + data: T, + filter: string +): boolean { + const keys = Object.keys(data); + return keys.some((property) => + entityListSortingAccessor(data, property) + ?.toString() + .toLowerCase() + .includes(filter) + ); +} From 975c0d6d2aa02dd733182e078889d3606351d60b Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 1 Jul 2021 18:11:46 +0200 Subject: [PATCH 222/230] fixed entity-form story --- .../entity-form/entity-form.stories.ts | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts index d13b44d79a..665c8b5bf1 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts @@ -13,6 +13,14 @@ import { ChildrenModule } from "../../../../child-dev-project/children/children. import { Router } from "@angular/router"; import { EntityFormModule } from "../entity-form.module"; import { EntityFormComponent } from "./entity-form.component"; +import { School } from "../../../../child-dev-project/schools/model/school"; + +const s1 = new School(); +s1.name = "First School"; +const s2 = new School(); +s2.name = "Second School"; +const s3 = new School(); +s3.name = "Third School"; export default { title: "Core/EntityComponents/EntityForm", @@ -26,7 +34,13 @@ export default { ChildrenModule, ], providers: [ - { provide: EntityMapperService, useValue: { save: () => null } }, + { + provide: EntityMapperService, + useValue: { + save: () => null, + loadType: () => Promise.resolve([s1, s2, s3]), + }, + }, { provide: AlertService, useValue: { addDanger: () => null, addInfo: () => null }, @@ -71,19 +85,15 @@ const cols = [ }, { edit: "EditLongText", - id: "additionalInfo", + id: "status", label: "Additional information", }, - { - edit: "EditBoolean", - id: "active", - label: "Is active", - }, { id: "gender" }, ], [ { edit: "EditConfigurableEnum", + view: "DisplayConfigurableEnum", id: "has_rationCard", label: "Ration Card Status", additional: "document-status", @@ -94,9 +104,22 @@ const cols = [ { id: "dateOfBirth", }, + { + id: "assignedTo", + edit: "EditEntityArray", + view: "DisplayEntityArray", + additional: "School", + label: "Assigned school(s)", + }, ], ]; +Child.schema.set("has_rationCard", { + dataType: "configurable-enum", + innerDataType: "document-status", +}); +Child.schema.set("assignedTo", { dataType: "array", innerDataType: "string" }); + const Template: Story = (args: EntityFormComponent) => ({ component: EntityFormComponent, props: args, From e8f1f3fb1604a51907731637f8f227339e1db85a Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 07:57:32 +0200 Subject: [PATCH 223/230] fixed changed after has been checked error --- .../entity-form/entity-form/entity-form.stories.ts | 2 +- .../entity-utils/entity-select/entity-select.component.html | 1 - .../entity-utils/entity-select/entity-select.component.ts | 4 ++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts index 665c8b5bf1..969df3188f 100644 --- a/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts +++ b/src/app/core/entity-components/entity-form/entity-form/entity-form.stories.ts @@ -37,7 +37,7 @@ export default { { provide: EntityMapperService, useValue: { - save: () => null, + save: () => Promise.resolve(), loadType: () => Promise.resolve([s1, s2, s3]), }, }, diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html index 6cad085afd..03edbe4365 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html @@ -3,7 +3,6 @@ implements OnChanges { * @param sel The initial selection */ @Input() set selection(sel: (string | E)[]) { + if (!Array.isArray(sel)) { + this.selection_ = []; + return; + } if (this.selectionInputType === "id") { this.loading .pipe( From c6b6031cd2c9ae6dfb376b8d894f0c88623bdb8c Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 08:23:00 +0200 Subject: [PATCH 224/230] fixed boolean filter default issue --- src/app/core/config/config-fix.ts | 1 - .../core/config/config-migration.service.spec.ts | 15 +++++++++++++++ src/app/core/config/config-migration.service.ts | 3 +++ .../entity-list/filter-generator.service.spec.ts | 6 +++--- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/app/core/config/config-fix.ts b/src/app/core/config/config-fix.ts index 82d3ca7632..1c49d28a05 100644 --- a/src/app/core/config/config-fix.ts +++ b/src/app/core/config/config-fix.ts @@ -278,7 +278,6 @@ export const defaultJsonConfig = { }, { "id": "privateSchool", - "default": "", "true": "Private School", "false": "Government School", "all": "All" diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index ae39f40097..dfd4296bb8 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -105,6 +105,14 @@ describe("ConfigMigrationService", () => { false: "Inactive", all: "All", }, + { + id: "isActiveAll", + type: "boolean", + default: "", + true: "Active Children", + false: "Inactive", + all: "All", + }, { id: "center", label: "Center", @@ -469,6 +477,13 @@ const expectedChildrenListConfig = { false: "Inactive", all: "All", }, + { + id: "isActiveAll", + type: "boolean", + true: "Active Children", + false: "Inactive", + all: "All", + }, { id: "center", label: "Center", diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 667dffb685..151dd9fce4 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -201,6 +201,9 @@ export class ConfigMigrationService { filter.type = "School"; filter.id = "schoolId"; } + if (filter.default === "") { + delete filter.default; + } } catch (e) { console.warn(`Failed to migrate filter ${filter.id}: ${e}`); } diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts index 121b160056..9bb5f05787 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts @@ -52,7 +52,7 @@ describe("FilterGeneratorService", () => { return { key: option.key, label: option.label }; }) ).toEqual([ - { key: "", label: "All" }, + { key: null, label: "All" }, { key: "true", label: "Private" }, { key: "false", label: "Government" }, ]); @@ -63,7 +63,7 @@ describe("FilterGeneratorService", () => { const interactionTypes = defaultInteractionTypes.map((it) => { return { key: it.id, label: it.label }; }); - interactionTypes.push({ key: "", label: "All" }); + interactionTypes.push({ key: null, label: "All" }); const schema = Note.schema.get("category"); const filter = (await service.generate([{ id: "category" }], Note, []))[0]; @@ -102,7 +102,7 @@ describe("FilterGeneratorService", () => { expect(filter.filterSettings.name).toEqual("schoolId"); const allRelations = [csr1, csr2, csr3, csr4]; const allFilter = filter.filterSettings.options.find( - (opt) => opt.key === "" + (opt) => opt.key === null ); expect(allFilter.label).toEqual("All"); expect(allRelations.filter(allFilter.filterFun)).toEqual(allRelations); From 9e2df4a53a832f2bd9cd697f361ee580dd46be07 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 09:25:16 +0200 Subject: [PATCH 225/230] fixed boolean filter default issue --- .../entity-components/entity-list/entity-list.component.ts | 2 -- .../entity-list/filter-generator.service.spec.ts | 6 +++--- .../entity-list/filter-generator.service.ts | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/app/core/entity-components/entity-list/entity-list.component.ts b/src/app/core/entity-components/entity-list/entity-list.component.ts index 5c1fd52888..5f50395ed9 100644 --- a/src/app/core/entity-components/entity-list/entity-list.component.ts +++ b/src/app/core/entity-components/entity-list/entity-list.component.ts @@ -24,8 +24,6 @@ import { EntitySubrecordComponent } from "../entity-subrecord/entity-subrecord/e import { FilterGeneratorService } from "./filter-generator.service"; import { FilterComponentSettings } from "./filter-component.settings"; import { entityFilterPredicate } from "./filter-predicate"; -import { FilterGeneratorService } from "./filter-generator.service"; -import { FilterComponentSettings } from "./filter-component.settings"; /** * This component allows to create a full blown table with pagination, filtering, searching and grouping. diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts index 9bb5f05787..8bb9111864 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.spec.ts @@ -52,7 +52,7 @@ describe("FilterGeneratorService", () => { return { key: option.key, label: option.label }; }) ).toEqual([ - { key: null, label: "All" }, + { key: "all", label: "All" }, { key: "true", label: "Private" }, { key: "false", label: "Government" }, ]); @@ -63,7 +63,7 @@ describe("FilterGeneratorService", () => { const interactionTypes = defaultInteractionTypes.map((it) => { return { key: it.id, label: it.label }; }); - interactionTypes.push({ key: null, label: "All" }); + interactionTypes.push({ key: "all", label: "All" }); const schema = Note.schema.get("category"); const filter = (await service.generate([{ id: "category" }], Note, []))[0]; @@ -102,7 +102,7 @@ describe("FilterGeneratorService", () => { expect(filter.filterSettings.name).toEqual("schoolId"); const allRelations = [csr1, csr2, csr3, csr4]; const allFilter = filter.filterSettings.options.find( - (opt) => opt.key === null + (opt) => opt.key === "all" ); expect(allFilter.label).toEqual("All"); expect(allRelations.filter(allFilter.filterFun)).toEqual(allRelations); diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index ca7e3420f3..83802b47a2 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -98,7 +98,7 @@ export class FilterGeneratorService { filter: BooleanFilterConfig ): FilterSelectionOption[] { return [ - { key: null, label: filter.all, filterFun: () => true }, + { key: "all", label: filter.all, filterFun: () => true }, { key: "true", label: filter.true, @@ -116,7 +116,7 @@ export class FilterGeneratorService { property: string, enumId: string ): FilterSelectionOption[] { - const options = [{ key: null, label: "All", filterFun: (e: T) => true }]; + const options = [{ key: "all", label: "All", filterFun: (e: T) => true }]; const enumValues = this.configService.getConfig( CONFIGURABLE_ENUM_CONFIG_PREFIX + enumId @@ -142,7 +142,7 @@ export class FilterGeneratorService { entityConstructor ); - const options = [{ key: null, label: "All", filterFun: (e: T) => true }]; + const options = [{ key: "all", label: "All", filterFun: (e: T) => true }]; options.push( ...filterEntities.map((filterEntity) => { return { From d86d7cf2110a6172e6b25c3d9d442a5d8b252c59 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 10:18:17 +0200 Subject: [PATCH 226/230] updated entity subrecord documentation --- .../entity-subrecord-component.md | 58 ++++++------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/doc/compodoc_sources/how-to-guides/entity-subrecord-component.md b/doc/compodoc_sources/how-to-guides/entity-subrecord-component.md index da128e9f0e..79212419f5 100644 --- a/doc/compodoc_sources/how-to-guides/entity-subrecord-component.md +++ b/doc/compodoc_sources/how-to-guides/entity-subrecord-component.md @@ -57,56 +57,32 @@ Unfortunately the implementation has to be a little clumsy: A method that itself Finally, the `[columns]` configuration allows you a lot of flexibility over which properties of the entities are shown and how they are formatted and edited. -This takes an array of [ColumnDescription](../../classes/ColumnDescription.html)s: +This takes an array of [FormFieldConfiguration](../../interfaces/FormFieldConfig.html)s: ``` -columns: Array = [ - new ColumnDescription('subject', 'Topic', ColumnDescriptionInputType.TEXT, null, undefined, 'xs'), - new ColumnDescription('text', 'Notes', ColumnDescriptionInputType.TEXTAREA, null, undefined, 'md'), - new ColumnDescription('date', 'Date', ColumnDescriptionInputType.DATE, null, (v: Date) => this.datePipe.transform(v, 'yyyy-MM-dd'), 'xs'), +columns: FormFieldConfig[] = [ + { id: 'subject', label: 'Topic', view: 'DisplayText', edit: 'EditText', visibleFrom: 'xs'), + { id: 'text', label: 'Notes', view: 'DisplayText', edit: 'EditLongText', visibleFrom: 'md'), + { id: 'date', label: 'Date', view: 'DisplayDate', edit: 'EditDate', visibleFrom: 'xs'), ]; ``` Only the properties that you set here will be displayed to the user. Use the parameters to configure transformations and form field types. +When a entity is displayed, most of the properties can be omitted and will be fetched from the schema definition > To learn about the full range of column options check out the API Reference: -> - [ColumnDescription](../../classes/ColumnDescription.html) -> - [ColumnDescriptionInputType](../../miscellaneous/enumerations.html#ColumnDescriptionInputType) +> - [FormFieldConfiguration](../../interfaces/FormFieldConfig.html) +> - [EntitySchemaField](../../interfaces/EntitySchemaField.html) ## Showing details of one entity The EntitySubrecordComponent allows the user to edit an entity inline in the table. -If you have more complex entities it can be more feasible to show the user a modal (overlay) component -with the details of a single entity when a row of the table is clicked. - -You can enable this optional behaviour by additionally setting the `[detailsComponent]` input property -of `` in your template. -This simply takes a Component class that will be used to display details of a single entity instance. - -To be able to use it in your template, you have to assign the Component class to a class variable: -``` -@Component({ - selector: 'app-notes', - template: '' + - '', -}) -export class ChildNotesComponent { - detailsComponent = { component: NoteDetailsComponent, config: { displayMode: 1 } }; -``` - -The Component used as "detailsComponent" receives the entity to be display as `MAT_DIALOG_DATA` like this: +By default, clicking on a row will automatically open a form popup which shows all editable fields of the table. +What happens when a row is clicked can be overwritten with the `[showEntity]` parameter. +This parameter expects a function that gets the clicked entity as input. ``` -export class NoteDetailsComponent implements OnInit, OnInitDynamicComponent { - private note: Note; - displayMode: number; - - constructor(@Inject(MAT_DIALOG_DATA) data: any) { - this.note = data.entity; - } - - async onInitFromDynamicConfig(config: any) { - this.displayMode = config.displayMode; - this.init(); - } + ``` -As shown above the (optional) config object is received by implementing the {@link OnInitDynamicComponent} -interface's `onInitFromDynamicConfig` method. From b9873e55a05e7fc14fe9006f601445dd14ed1257 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 10:29:54 +0200 Subject: [PATCH 227/230] added documentation for schema system --- .../concepts/entity-schema-system.md | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/doc/compodoc_sources/concepts/entity-schema-system.md b/doc/compodoc_sources/concepts/entity-schema-system.md index ea61ecb590..5054a5545a 100644 --- a/doc/compodoc_sources/concepts/entity-schema-system.md +++ b/doc/compodoc_sources/concepts/entity-schema-system.md @@ -1,6 +1,4 @@ # Entity Schema -> THIS DOCUMENT IS STILL WORK IN PROGRESS AND WILL BE CONTINUOUSLY UPDATED AS THE DESIGN OF THE SYSTEM EVOLVES - ----- An example of a schema definition: @@ -21,22 +19,27 @@ class Note extends Entity { The logical flow looks something like this: 1. Entities are requested through the `EntityMapperService` (`entityMapper.load(...)`) 2. The `EntitySchemaService` functions as a helper to the `EntityMapperService` -and takes care of data transformations based on the schema of that Entity type. -3. Data from the database is "loaded" into an Entity instance to combine the raw data -with its Entity class by the `EntityMapperService` together with the `EntitySchemaService`. -4. The Entity classes themselves only define the schema through the `@DatabaseEntity` and `@DatabaseField` decorators +and takes care of data transformations based on the schema of that entity type. +3. Data from the database is "loaded" into an entity instance to combine the raw data +with its entity class by the `EntityMapperService` together with the `EntitySchemaService`. +4. The entity classes themselves only define the schema through the `@DatabaseEntity` and `@DatabaseField` decorators and are otherwise simple Typescript objects. -The process of saving an Entity to the database works similarly with `EntitySchemaService` +The process of saving an entity to the database works similarly with `EntitySchemaService` supporting the `EntityMapperService` and transforming the entity object into the desired format to be persisted into the database. ----- - - `EntitySchemaService` keeps a registry of "data types", i.e. transformation functions that will be called for a specific schema field's dataType. Basic data transformations for `string`, `number`, `date` and `month` are supported by default. You can register your own transformations by injecting the `EntitySchemaService` and using its `registerSchemaDatatype()` method. + +## Schema options + +The schema definitions contains information regarding the schema transformation as well as how a property can be displayed. +The [EntitySchemaField](../../interfaces/EntitySchemaField.html) interface shows all configuration options. +If the `editComponent` and the `viewComponent` are not set, the default components of this property's datatype will be used. +The `description` field allows adding further explanation which will be displayed as a tooltip. From 4a87530adf5f5682a35f3814f62f58acee7c6f0b Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 12:09:04 +0200 Subject: [PATCH 228/230] updated documentation for config system --- .../concepts/configuration.md | 242 +++--------------- 1 file changed, 33 insertions(+), 209 deletions(-) diff --git a/doc/compodoc_sources/concepts/configuration.md b/doc/compodoc_sources/concepts/configuration.md index 2ce462e76e..f1a4eb8f0c 100644 --- a/doc/compodoc_sources/concepts/configuration.md +++ b/doc/compodoc_sources/concepts/configuration.md @@ -145,7 +145,9 @@ List components showing data in a table (such as ChildrenList oder SchoolsList) The `"title"` is the text shown in the heading of the component. -`"columns"` contains an array of the columns to be displayed. Each column-entry has the three fields `"component"`, `"title"` and `"id"`. +`"columns"` contains an array of the columns to be displayed. +The configuration for the columns happens with the [FormFieldConfiguration](../../interfaces/FormFieldConfig.html) interface. +If all the information is available on the schema or through the datatype of a property, it is sufficient to put a string with the name of the property into the columns array. Example: ``` @@ -154,16 +156,12 @@ Example: "config": { "title": "Children List", "columns": [ - { - "component": "DisplayText", - "title": "PN", - "id": "projectNumber" - }, - { - "component": "ChildBlock", - "title": "Name", - "id": "name" - } + "projectNumber", + { + "view": "ChildBlock", + "label": "Name", + "id": "name" + }, ... ``` @@ -171,7 +169,8 @@ The `"columnGroup"` object holds the three properties `"default"`, `"mobile"` an `"default"` and `"mobile"` hold the names of the group of columns being displayed by default or on a mobile device. If the `"columnGroup"` property is not defined, all columns will be displayed. If `"default"` or `"mobile"` is not defined, the first entry of `"groups"` will be used. -`"groups"` consists of an array of groups of columns, where every entry has a `"name"` and an array of column names within `"columns"`. +`"groups"` consists of an array of groups of columns, where every entry has a `"name"` and an array of column ids within `"columns"`. +Properties that are listed in any of the `groups` arrays and don't require further configurations, can be omitted from the `columns` array, the `EntityListComponent` will automatically add them. Example: ``` @@ -200,13 +199,10 @@ Example: ``` The object `"filters"` within the config of a list component can be used to create filter options for the list data. -Currently, three types of filters exist: default, boolean and prebuilt. -For default and boolean filters, the `"id"` field refers to an attribute of the entity which is displayed in the list. -The default filter only requires the field `"id"` and will provide filter options for all possible values of this property. -A boolean filter can be specified with `"type": "boolean"` and requires the fields `"id"`, `"default"`, `"true"`, `"false"` and `"all"` to be set. +The type of filter will be automatically determined by the datatype of that property. +The filters allow to filter the table by the possible values of a property. This will create a filter for boolean values with three buttons (`all`, `true`, `false`). The names of these buttons can be specified using the `"true"`, `"false"` and `"all"` option. -The `"default"` options defines which button should be active on default and has to be `""`, `"true"` or `"false"`. The prebuilt option is used to enable or disable filters that contain more logic and are implemented inside the component which is displayed. This option requires the fields `"type"` and `"id"`, where `"id"` matched the `id` of a prebuilt filter inside a component. @@ -218,8 +214,7 @@ Example: }, { "id": "privateSchool", - "type": "boolean", - "default": "", + "default": "all", "true": "Private School", "false": "Government School", "all": "All" @@ -283,61 +278,22 @@ It allows to dynamically create a form through configuration. The configuration for this component expects a single field, the `"cols"`. This field should be a two dimensional array where the first dimension defines what is rendered next to each other (the columns), and the second dimension what is rendered in each column. If all fields are the same height, then every field can be defined as a column. -The inner object can have the following but not always required fields: `"input"`, `"id"`, `"placeholder"`, `"required"`, `"options"` and `"enumId"`. -`"input"` defines which input type should be used. -`"id"` defines the entity attribute which should be displayed and modified. -`"placeholder"` defines a value that is displayed if no value is present. -`"required"` specifies whether a value is required, default is `false`. -`"options"` is only required when `"input": "select"` and defines the available select options. -`"enumId"` is only required when `"input": "configurable-enum-select"` and refers to the config id of the enum that should be used for the select options. +The definitions for the columns is defined by the [FormFieldConfiguration](../../interfaces/FormFieldConfig.html) +However, the schema definitions of the entity should be sufficient so that only the names of the properties which should be editable in the form have to be provided. +This means instead of placing an object in the `cols` array, simple strings do the same job. ``` "config": { "cols": [ [ - { - "input": "photo", - "id": "photoFile", - "placeholder": "Photo Filename" - } + "photo" ], [ - { - "input": "text", - "id": "name", - "placeholder": "Name", - "required": true - }, - { - "input": "text", - "id": "projectNumber", - "placeholder": "Project Number" - } + "name" + "projectNumber" ], [ - { - "input": "age" - }, - { - "input": "datepicker", - "id": "dateOfBirth", - "placeholder": "Date of Birth" - }, - { - "input": "select", - "id": "gender", - "placeholder": "Gender", - "options": [ - "M", - "F" - ], - }, - { - "input": "configurable-enum-select", - "id": "has_aadhar", - "placeholder": "Aadhar Status", - "enumId": "document-status" - }, + "dateOfBirth" ] ] } @@ -349,23 +305,20 @@ It can be configured which attributes of the `ChildSchoolRelation` are shown in Possible configurations are `single` and `columns` which are both optional. `single` is a boolean and if is set to `true` the component will show which (if any) school the child is currently attending. This should only be set to `true`, when the use-case only allows one active school per child. -`columns` is an object and determines which columns are shown and how the columns are called. -If `columns` is set, then `schoolId`, `start` and `end` need to be defined. -`schoolClass` and `result` are optional. -The value of a field determines the name of the column, e.g. setting `schoolId: School` will give the column which displays the schools the name `School`. -If `schoolClass` or `result` is not defined, then the respective column will not be visible. +`columns` is an object and determines which columns of the `ChildSchoolRelation` are shown. +The configuration is according to the [EntitySubrecordComponent](../how-to-guides/entity-subrecord-component.md); Example: ``` "config": { "single": true, - "columns": { - "schoolId": "School", - "schoolClass": "Class", - "start": "From", - "end": "To", - "result": "Result" - } + "columns": [ + "schoolId", + "schoolClass", + "start", + "end", + "result", + ], } ``` @@ -381,10 +334,10 @@ Example: ``` "entity:Child": { "attributes": [ - {"name": "address", "schema": { "dataType": "string" } }, - {"name": "phone", "schema": { "dataType": "string" } }, + {"name": "address", "schema": { "dataType": "string", "label": "Address" } }, + {"name": "phone", "schema": { "dataType": "string", "label": "Phone number" } }, ... - {"name": "health_lastDeworming", "schema": { "dataType": "Date" } } + {"name": "health_lastDeworming", "schema": { "dataType": "Date", "label": "Last deworming" } } ] } @@ -555,132 +508,3 @@ Example: "countAs": "IGNORE" } ``` - - ------ -## Example - -An example of a full config file: - -``` -{ - "navigationMenu": { - "items": [ - {"name": "Dashboard", "icon": "home", "link": "/dashboard"}, - {"name": "Children", "icon": "child", "link": "/child"}, - {"name": "Schools", "icon": "university", "link": "/school"}, - {"name": "Notes", "icon": "file-text", "link": "/note"}, - {"name": "Attendance Register", "icon": "table", "link": "/attendance"}, - {"name": "Admin", "icon": "wrench", "link": "/admin"}, - {"name": "Users", "icon": "user", "link": "/users"}, - {"name": "Database Conflicts", "icon": "wrench", "link": "/admin/conflicts"}, - {"name": "Help", "icon": "question-circle", "link": "/help"} - ] - }, - "notes": { - "InteractionTypes": { - "NONE": {"name": ""}, - "HOME_VISIT": {"name": "Home Visit"}, - "GUARDIAN_TALK": {"name": "Talk with Guardians"}, - "CHILD_TALK": {"name": "Talk with Child"}, - "INCIDENT": {"name": "Incident"}, - "DISCUSSION": {"name": "Discussion/Decision", "color": "#E1BEE7"}, - "VISIT": {"name": "School/Hostel Visit"}, - "PHONE_CALL": {"name": "Phone Call"}, - "COACHING_TALK": {"name": "Talk with Coaching Teacher"}, - "PEER_TALK": {"name": "Talk with Peer"}, - "NEIGHBOUR_TALK": {"name": "Talk with Neighbours"}, - "GUARDIAN_MEETING": {"name": "Guardians' Meeting", "color": "#E1F5FE", "isMeeting": true}, - "CHILDREN_MEETING": {"name": "Children's Meeting", "color": "#E1F5FE", "isMeeting": true}, - "DAILY_ROUTINE": {"name": "Daily Routine", "color": "#F1F8E9"}, - "ANNUAL_SURVEY": {"name": "Annual Survey", "color": "#FFFDE7"}, - "EXCURSION": {"name": "Excursion/Trip", "color": "#E1F5FE", "isMeeting": true}, - "PARTNER_CONTACT": {"name": "Contact with other partners (club/NGO/...)"}, - "RATION_DISTRIBUTION": {"name": "Ration Distribution", "color": "#E1F5FE", "isMeeting": true} - } - }, - "view:": { - "component": "Dashboard", - "config": { - "widgets": [ - { - "component": "ChildrenCountDashboard" - }, - { - "component": "RecentNotesDashboard" - }, - { - "component": "NoRecentNotesDashboard", - "config": { - "sinceDays": 28, - "fromBeginningOfWeek": false - } - }, - { - "component": "AttendanceWeekDashboard", - "config": { - "daysOffset": 0, - "periodLabel": "last week" - } - }, - { - "component": "AttendanceWeekDashboard", - "config": { - "daysOffset": 7, - "periodLabel": "this week" - } - }, - { - "component": "ProgressDashboard", - "config": { - "dashboardConfigId": "1" - } - }, - { - "component": "AttendanceAverageDashboard" - }, - { - "component": "AttendanceWarningsDashboard" - } - ] - } - }, - "view:user": {"component": "UserAccount"}, - "view:note": {"component": "NotesManager", "config": { "title": "Notes & Reports"}}, - "view:admin": {"component": "Admin", "requiresAdmin": true}, - "view:users": {"component": "UserList", "requiresAdmin": true}, - "view:help": {"component": "Help"}, - "view:attendance": {"component": "AttendanceManager"}, - "view:attendance/analysis": {"component": "AttendanceAnalysis"}, - "view:attendance/add/month": {"component": "AddMonthAttendance"}, - "view:attendance/add/day": {"component": "AddDayAttendance"}, - - "view:school": {"component": "SchoolsList", "config": { "title": "Schools List"} }, - "view:school/:id": { - "component": "SchoolDetails", - "config": { - "submenu": [ - { - "name": "Education", - "components": ["previousSchools", "aserResults"] - } - ], - "icon": "university" - } - }, - "view:child": {"component": "ChildrenList", "config": { "title": "Children List"} }, - "view:child/:id": { - "component": "ChildDetails", - "config": { - "submenu": [ - { - "name": "Education", - "components": ["previousSchools", "aserResults"] - } - ], - "icon": "child" - } - } -} - -``` From 96ae9dd4f83dbc47dffd23fd02d5944f9da81107 Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 2 Jul 2021 12:27:45 +0200 Subject: [PATCH 229/230] added migration for assignedTo filters --- src/app/core/config/config-migration.service.spec.ts | 9 +++++++++ src/app/core/config/config-migration.service.ts | 4 ++++ .../entity-list/filter-generator.service.ts | 8 +++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/app/core/config/config-migration.service.spec.ts b/src/app/core/config/config-migration.service.spec.ts index dfd4296bb8..7147bee6ab 100644 --- a/src/app/core/config/config-migration.service.spec.ts +++ b/src/app/core/config/config-migration.service.spec.ts @@ -126,6 +126,9 @@ describe("ConfigMigrationService", () => { label: "School", display: "dropdown", }, + { + id: "assignedTo", + }, ], }, }, @@ -495,6 +498,12 @@ const expectedChildrenListConfig = { label: "School", display: "dropdown", }, + { + id: "assignedTo", + type: "User", + label: "Assigned user(s)", + display: "dropdown", + }, ], }, }; diff --git a/src/app/core/config/config-migration.service.ts b/src/app/core/config/config-migration.service.ts index 151dd9fce4..e6ecb494c3 100644 --- a/src/app/core/config/config-migration.service.ts +++ b/src/app/core/config/config-migration.service.ts @@ -200,6 +200,10 @@ export class ConfigMigrationService { } else if (filter.id === "school") { filter.type = "School"; filter.id = "schoolId"; + } else if (filter.id === "assignedTo") { + filter.type = "User"; + filter.label = "Assigned user(s)"; + filter.display = "dropdown"; } if (filter.default === "") { delete filter.default; diff --git a/src/app/core/entity-components/entity-list/filter-generator.service.ts b/src/app/core/entity-components/entity-list/filter-generator.service.ts index 83802b47a2..0442179e1d 100644 --- a/src/app/core/entity-components/entity-list/filter-generator.service.ts +++ b/src/app/core/entity-components/entity-list/filter-generator.service.ts @@ -148,7 +148,13 @@ export class FilterGeneratorService { return { key: filterEntity.getId(), label: filterEntity.toString(), - filterFun: (entity) => entity[property] === filterEntity.getId(), + filterFun: (entity) => { + if (Array.isArray(entity[property])) { + return entity[property].includes(filterEntity.getId()); + } else { + return entity[property] === filterEntity.getId(); + } + }, }; }) ); From 68d7abdddc0b72e05e8c7c9c32a0c29083ae9f21 Mon Sep 17 00:00:00 2001 From: Sebastian Leidig Date: Sat, 3 Jul 2021 00:02:43 +0200 Subject: [PATCH 230/230] hide entity-select input field when disabled while still avoiding changed after checked error --- .../entity-select/entity-select.component.html | 1 + .../entity-utils/entity-select/entity-select.stories.ts | 9 +++++++++ .../entity-utils/entity-utils.module.ts | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html index 03edbe4365..6451d5e59c 100644 --- a/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html +++ b/src/app/core/entity-components/entity-utils/entity-select/entity-select.component.html @@ -3,6 +3,7 @@