src/app/child-dev-project/notes/model/note.ts
Notes are a special in-built entity type to record free-form information related to other records.
Previously, Note has also functioned to record an event with an attendance list of participants.
That functionality is getting generalized and decoupled from this specific entity.
Add a "attendance" type field to any entity type instead.
Note therefore no longer declares the legacy children, schools and childrenAttendance fields.
Systems that still hold data in them have the definitions written into their own entity:Note config
by the v4-upgrade-note-legacy-child-school-fields CLI migration
(see deprecated/legacy-note-fields.ts).
No results matching.
Properties |
|
Methods |
|
| attachment |
Type : string
|
Decorators :
@DatabaseField({label: undefined, dataType: 'file'})
|
| category |
Type : InteractionType
|
Decorators :
@DatabaseField({label: undefined, dataType: 'configurable-enum', additional: INTERACTION_TYPE_CONFIG_ID, anonymize: 'retain'})
|
| date |
Type : Date
|
Decorators :
@DatabaseField({label: undefined, dataType: 'date-only', defaultValue: undefined, anonymize: 'retain'})
|
| Static hasPII |
Type : unknown
|
Default value : true
|
|
Inherited from
Entity
|
| Static icon |
Type : IconName
|
Default value : "file-alt"
|
|
Inherited from
Entity
|
| Static label |
Type : unknown
|
Default value : $localize`:label for entity:Note`
|
|
Inherited from
Entity
|
| Static labelPlural |
Type : unknown
|
Default value : $localize`:label (plural) for entity:Notes`
|
| relatesTo |
Type : string
|
Decorators :
@DatabaseField({anonymize: 'retain'})
|
|
id referencing a different entity (e.g. a recurring activity) this note is related to |
| subject |
Type : string
|
Decorators :
@DatabaseField({label: undefined})
|
| text |
Type : string
|
Decorators :
@DatabaseField({label: undefined, dataType: 'long-text'})
|
| Static toStringAttributes |
Type : []
|
Default value : ["subject"]
|
|
Inherited from
Entity
|
| warningLevel |
Type : Ordering.EnumValue
|
Decorators :
@DatabaseField({label: undefined, dataType: 'configurable-enum', additional: 'warning-levels', anonymize: 'retain'})
|
| Static Optional _isCustomizedType |
| todo: This property is no longer used and will be removed in future versions. |
Type : boolean
|
|
Inherited from
Entity
|
|
True if this type's schema has been customized dynamically from the config. |
| _rev |
Type : string
|
Decorators :
@DatabaseField({anonymize: 'retain', isInternalField: true})
|
|
Inherited from
Entity
|
|
internal database doc revision, used to detect conflicts by PouchDB/CouchDB |
| anonymized |
Type : boolean
|
Decorators :
@DatabaseField({anonymize: 'retain', isInternalField: true})
|
|
Inherited from
Entity
|
|
Whether this entity has been anonymized and therefore cannot be re-activated. |
| Static color |
Type : string | ColorMapping[]
|
|
Inherited from
Entity
|
|
color used for to highlight this entity type across the app. Can be either:
|
| created |
Type : UpdateMetadata
|
Decorators :
@DatabaseField({anonymize: 'retain', isInternalField: true})
|
|
Inherited from
Entity
|
| Static DATABASE |
Type : string
|
Default value : "app"
|
|
Inherited from
Entity
|
|
The database where these entities are stored. |
| Static Readonly DATABASE_REMOTE_ONLY |
Type : boolean
|
Default value : false
|
|
Inherited from
Entity
|
|
Whether DATABASE exists on the server only and must never be replicated to the device. Such a database is opened as a remote handle, is not watched for changes, and is left untouched when local databases are reset or destroyed. Use it for data that grows without bound or that the client must not keep a copy of. |
| Static Optional enableUserAccounts |
Type : boolean
|
|
Inherited from
Entity
|
|
Whether to enable user account creation for this entity type. When true, the UI will allow management of user accounts associated with this entity. |
| Static ENTITY_TYPE |
Type : string
|
Default value : "Entity"
|
|
Inherited from
Entity
|
|
The entity's type.
In classes extending Entity this is usually overridden by the class annotation |
| inactive |
Type : boolean
|
Decorators :
@DatabaseField({anonymize: 'retain', isInternalField: true})
|
|
Inherited from
Entity
|
| Static Optional isInternalEntity |
Type : boolean
|
|
Inherited from
Entity
|
|
if this entity type is an internal entity, i.e. only defined in the code base to store internal system data and not visible to the user for customization. |
| Static schema |
Type : EntitySchema
|
|
Inherited from
Entity
|
|
EntitySchema defining property transformations from/to the database.
This is auto-generated from the property annotations see /additional-documentation/how-to-guides/create-a-new-entity-type.html |
| Static Optional toBlockDetailsAttributes |
Type : EntityBlockConfig
|
|
Inherited from
Entity
|
|
Defining which attributes will be displayed in a tooltip on hover when the record is displayed as an entity-block. |
| updated |
Type : UpdateMetadata
|
Decorators :
@DatabaseField({anonymize: 'retain', isInternalField: true})
|
|
Inherited from
Entity
|
| Static create | ||||||||||||||||
create(date: Date, subject: string, relatedEntities: string[])
|
||||||||||||||||
|
Parameters :
Returns :
Note
|
| Public getColor |
getColor()
|
|
Inherited from
Entity
|
|
Returns :
any
|
| Public getColorForId | ||||||
getColorForId(participantId: string)
|
||||||
|
Special color override to reflect the attendance status for a specific participant. Looks at whichever attendance field the (config-extended) schema has,
i.e. the modern
Parameters :
Returns :
string
|
| Static getPropertyFor | ||||||
getPropertyFor(entityType: string)
|
||||||
|
Returns the name of the Note property where (multiple) entities of the given entity type are stored:
the first "entity" array field configured for that type (e.g.
Parameters :
Returns :
string
|
| getWarningLevel |
getWarningLevel()
|
|
Inherited from
Entity
|
|
Returns :
WarningLevel
|
| assertValid |
assertValid()
|
|
Inherited from
Entity
|
|
Checks if the entity is valid and if the check fails, throws an error explaining the failed check.
Returns :
void
|
| Public copy | ||||||||||
copy(newId: string | boolean)
|
||||||||||
|
Inherited from
Entity
|
||||||||||
|
Deep copy of the entity. The resulting entity will be of the same type as this (taking into account subclassing). All schema field values that are objects or arrays are deep-cloned to avoid shared mutable state between original and copy.
Parameters :
Returns :
unknown
|
| Static createPrefixedId | ||||||||||||
createPrefixedId(type: string, id: string)
|
||||||||||||
|
Inherited from
Entity
|
||||||||||||
|
Create a prefixed id by adding the type prefix if it isn't already part of the given id.
Parameters :
Returns :
string
|
| Static extractEntityIdFromId | ||||||||
extractEntityIdFromId(id: string)
|
||||||||
|
Inherited from
Entity
|
||||||||
|
Extract entityId without prefix.
Parameters :
Returns :
string
|
| Static extractTypeFromId | ||||||||
extractTypeFromId(id: string)
|
||||||||
|
Inherited from
Entity
|
||||||||
|
Extract the ENTITY_TYPE from an id.
Parameters :
Returns :
string
|
| Static getColorWithConditions | ||||||
getColorWithConditions(entity: Entity)
|
||||||
|
Inherited from
Entity
|
||||||
|
Static method to evaluate conditional colors for an entity based on ColorMapping configuration.
Parameters :
Returns :
string
|
| getConstructor |
getConstructor()
|
|
Inherited from
Entity
|
|
Get the class (Entity or the actual subclass of the instance) to call static methods on the correct class considering inheritance
Returns :
EntityConstructor<unknown>
|
| Public getId | ||||||||
getId(withoutPrefix: unknown)
|
||||||||
|
Inherited from
Entity
|
||||||||
|
Returns the id of this entity. Note that an id is final and can't be changed after the object has been instantiated, hence there is no
Parameters :
Returns :
string
the unique id of this entity |
| getSchema |
getSchema()
|
|
Inherited from
Entity
|
|
Get the entity schema of this class
Returns :
EntitySchema
|
| Public getType |
getType()
|
|
Inherited from
Entity
|
|
Returns the type which is used to categorize this entity in the database. Important: Do not overwrite this method! Types are handled internally.
Returns :
string
the entity's type (which is the class name). |
import { DatabaseEntity } from "../../../core/entity/database-entity.decorator";
import { Entity } from "../../../core/entity/model/entity";
import { DatabaseField } from "../../../core/entity/database-field.decorator";
import {
INTERACTION_TYPE_CONFIG_ID,
InteractionType,
} from "./interaction-type.interface";
import { AttendanceItem } from "#src/app/features/attendance/model/attendance-item";
import { AttendanceLogicalStatus } from "#src/app/features/attendance/model/attendance-status";
import { AttendanceDatatype } from "#src/app/features/attendance/model/attendance.datatype";
import { getWarningLevelColor, WarningLevel } from "../../warning-level";
import { Ordering } from "../../../core/basic-datatypes/configurable-enum/configurable-enum-ordering";
import { PLACEHOLDERS } from "../../../core/entity/schema/entity-schema-field";
import { IconName } from "@fortawesome/fontawesome-svg-core";
import { asArray } from "../../../utils/asArray";
/**
* Notes are a special in-built entity type to record free-form information related to other records.
*
* Previously, `Note` has also functioned to record an event with an attendance list of participants.
* That functionality is getting generalized and decoupled from this specific entity.
* Add a "attendance" type field to any entity type instead.
*
* `Note` therefore no longer declares the legacy `children`, `schools` and `childrenAttendance` fields.
* Systems that still hold data in them have the definitions written into their own `entity:Note` config
* by the `v4-upgrade-note-legacy-child-school-fields` CLI migration
* (see `deprecated/legacy-note-fields.ts`).
*/
@DatabaseEntity("Note")
export class Note extends Entity {
static override toStringAttributes = ["subject"];
static override label = $localize`:label for entity:Note`;
static override labelPlural = $localize`:label (plural) for entity:Notes`;
static override icon: IconName = "file-alt";
static override hasPII = true;
static create(
date: Date,
subject: string = "",
relatedEntities: string[] = [],
): Note {
const instance = new Note();
instance.date = date;
instance.subject = subject;
instance.relatedEntities = [...relatedEntities];
return instance;
}
/**
* All Note properties that link this note to other records,
* i.e. every "entity" field in the (config-extended) schema except `authors`.
*
* This covers the generic `relatedEntities` as well as any custom or legacy entity fields of a system.
* (`authors` is indexed and queried separately.)
*/
static getLinkFields(): string[] {
return [...Note.schema.entries()]
.filter(
([key, field]) => field.dataType === "entity" && key !== "authors",
)
.map(([key]) => key)
.sort((a, b) => a.localeCompare(b));
}
/**
* Returns the name of the Note property where (multiple) entities of the given entity type are stored:
* the first "entity" array field configured for that type (e.g. `relatedEntities` or a legacy `children` field).
* If no field is configured for that type, `relatedEntities` is returned as fallback,
* so that the entity is still linked to the note.
* `authors` is never returned, even for "User" entities.
* @param entityType
*/
static getPropertyFor(entityType: string): string {
const matchingField = [...Note.schema.entries()].find(
([key, field]) =>
key !== "authors" &&
field.dataType === "entity" &&
field.isArray &&
asArray(field.additional).includes(entityType),
);
return matchingField?.[0] ?? "relatedEntities";
}
@DatabaseField({
label: $localize`:Label for the date of a note:Date`,
dataType: "date-only",
defaultValue: {
mode: "dynamic",
config: { value: PLACEHOLDERS.NOW },
},
anonymize: "retain",
})
date: Date;
@DatabaseField({
label: $localize`:Label for the subject of a note:Subject`,
})
subject: string;
@DatabaseField({
label: $localize`:Label for the actual notes of a note:Notes`,
dataType: "long-text",
})
text: string;
/** IDs of users that authored this note */
@DatabaseField({
label: $localize`:Label for the social worker(s) who created the note:Team involved`,
dataType: "entity",
isArray: true,
additional: "User",
defaultValue: {
mode: "dynamic",
config: { value: PLACEHOLDERS.CURRENT_USER },
},
anonymize: "retain",
})
authors: string[] = [];
@DatabaseField({
label: $localize`:Label for the category of a note:Category`,
dataType: "configurable-enum",
additional: INTERACTION_TYPE_CONFIG_ID,
anonymize: "retain",
})
category: InteractionType;
@DatabaseField({
label: $localize`Attachment`,
dataType: "file",
})
attachment: string;
/**
* id referencing a different entity (e.g. a recurring activity) this note is related to
*/
@DatabaseField({
anonymize: "retain",
})
relatesTo: string;
/**
* other records (e.g. a recurring activity, group membership, ...) to which this note is related in some way,
* so that notes can be displayed linked to these entities.
*
* This property saves ids including their entity type prefix.
*/
@DatabaseField({
label: $localize`:label for the related Entities:Related Records`,
dataType: "entity",
isArray: true,
// the code definition links no entity type: systems configure the linked types as `additional` in their config
// (as the base configs and the CLI migration of the legacy children / schools fields do)
additional: undefined,
anonymize: "retain",
})
relatedEntities: string[] = [];
@DatabaseField({
label: $localize`:Status of a note:Status`,
dataType: "configurable-enum",
additional: "warning-levels",
anonymize: "retain",
})
warningLevel: Ordering.EnumValue;
override getWarningLevel(): WarningLevel {
if (this.warningLevel) {
return WarningLevel[this.warningLevel.id];
} else {
return WarningLevel.NONE;
}
}
public override getColor() {
const actualLevel = this.getWarningLevel();
if (actualLevel === WarningLevel.OK || actualLevel === WarningLevel.NONE) {
return this.category?.color;
} else {
return super.getColor();
}
}
/**
* Special color override to reflect the attendance status for a specific participant.
*
* Looks at whichever attendance field the (config-extended) schema has,
* i.e. the modern `attendance` datatype as well as the legacy `event-attendance-map`.
*/
public getColorForId(participantId: string): string {
if (this.category?.isMeeting && this.isMarkedAbsent(participantId)) {
// participant is absent, highlight the entry
return getWarningLevelColor(WarningLevel.URGENT);
}
return this.getColor();
}
// This scans the whole schema for attendance fields on every call (per row and change detection in tables).
// If this becomes a performance issue, resolve the attendance field ids once per entity constructor instead.
private isMarkedAbsent(participantId: string): boolean {
return AttendanceDatatype.detectAllFieldsInEntity(
this.getConstructor(),
).some(({ fieldId }) =>
(this[fieldId] as AttendanceItem[] | undefined)?.some(
(item) =>
item?.participant === participantId &&
item?.status?.countAs === AttendanceLogicalStatus.ABSENT,
),
);
}
}