Index

src/app/core/basic-datatypes/date/date.static.ts

_dateFormat
Type : unknown
Default value : signal("dd.MM.yyyy")
_datepickerFormat
Type : unknown
Default value : signal("DD.MM.YYYY")
_dateTimeFormat
Type : unknown
Default value : signal("dd.MM.yyyy HH:mm")
datepickerFormat
Type : Signal<string>
Default value : _datepickerFormat.asReadonly()

Current Moment.js format for Material Datepicker as a readonly signal (e.g., "DD.MM.YYYY"). We have to use different format for datepicker because Angular DatePipe and Moment.js use different format syntax: e.g. dd.MM.yyyy in DatePipe shows as 22.01.2026, but in Moment.js it would show as Th.01.2026.

defaultDateFormat
Type : Signal<string>
Default value : _dateFormat.asReadonly()

Current default shortDate format as a readonly signal (Angular DatePipe format, e.g., "dd.MM.yyyy")

defaultDateTimeFormat
Type : Signal<string>
Default value : _dateTimeFormat.asReadonly()

Current default datetime format as a readonly signal (Angular DatePipe format, e.g., "dd.MM.yyyy HH:mm")

src/app/child-dev-project/notes/demo-data/remarks.ts

absenceRemarks
Type : []
Default value : [ $localize`:Absence remark:got excused by it's mother`, $localize`:Absence remark:absent without excuse`, $localize`:Absence remark:absent because ill`, "", "", "", ]

src/app/features/change-history/change-history-action-badge/change-history-action-badge.component.ts

ACTION_META
Type : Record<ChangeAction, ActionMeta>
Default value : { baseline: { icon: "clock-rotate-left", label: $localize`:Change action badge:Initial snapshot`, background: "#ECEFF1", color: "#4a525c", tooltip: BASELINE_NOTE, }, created: { icon: "circle-plus", label: $localize`:Change action badge:Created`, background: "#E6F4EA", color: "#1E6C33", }, updated: { icon: "pen-to-square", label: $localize`:Change action badge:Updated`, background: "#CCEFFF", color: "#1565C0", }, deleted: { icon: "trash", label: $localize`:Change action badge:Deleted`, background: "#FBE2DE", color: "#B23A2C", }, }

Display metadata per action. Orange is reserved for app chrome, so even imported uses an orange-tint background with deep-orange text — never the brand primary fill.

src/app/core/permissions/permission-types.ts

actions
Type : unknown
Default value : [ "read", "create", "update", "delete", "manage", // Matches any actions ] as const

The list of action strings that can be used for permissions

ADMIN_APP_ROLE
Type : string
Default value : "admin_app"

The realm role that grants access to the administration features, as checked by the admin routes' UserRoleGuard configuration.

DEFAULT_SECTION_KEY
Type : string
Default value : "_default"

Section keys in DatabaseRules that carry special semantics instead of mapping a user role. The underscore prefix marks them as internal so they cannot collide with a realm role name.

PUBLIC_SECTION_KEY
Type : string
Default value : "_public"
RESERVED_ROLE_PREFIX
Type : string
Default value : "_"

A user role starting with this prefix is reserved and never resolved.

RESERVED_RULE_CONFIG_KEYS
Type : miscellaneous
Default value : [ DEFAULT_SECTION_KEY, PUBLIC_SECTION_KEY, ]

All section keys that must never be resolved as if they were user role names, even if a realm role with the same name exists.

A new key added here does not automatically stop inheriting the "_default" rules; see inheritsDefaultRules.

src/app/features/attendance/demo-data/demo-activity-generator.service.ts

ACTIVITY_TYPES
Type : unknown
Default value : [ defaultInteractionTypes.find((t) => t.id === "SCHOOL_CLASS"), defaultInteractionTypes.find((t) => t.id === "COACHING_CLASS"), ].filter((t): t is InteractionType => t !== undefined)

src/app/child-dev-project/notes/add-default-note-views.ts

addDefaultNoteDetailsConfig
Type : ConfigMigration
Default value : ( key, configPart, ) => { if (configPart?.["_id"] !== "Config:CONFIG_ENTITY" || !configPart?.["data"]) { // add only at top-level of config return configPart; } if (!configPart?.["data"]["view:note/:id"]) { configPart["data"]["view:note/:id"] = { component: "NoteDetails", config: getDefaultNoteDetailsConfig(), }; } return configPart; }

Add default view:note/:id NoteDetails config to avoid breaking note details with a default config from AdminModule

src/app/features/todos/add-default-todo-views.ts

addDefaultTodoViews
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.["_id"] !== "Config:CONFIG_ENTITY" || !configPart?.["data"]) { // add only at top-level of config return configPart; } const configData = configPart["data"]; const viewConfigKey = `view:${Todo.route.substring(1) /* remove leading slash */}`; // List View if (!configData[viewConfigKey]) { // add standard list view configData[viewConfigKey] = JSON.parse(JSON.stringify(defaultTodoListView)); } else { // add prebuilt filter to existing list view const existingFilters = configData[viewConfigKey].config.filters || []; if (!existingFilters.some((f) => f.id === todoDueStatusFilter.id)) { // reference the prebuilt filter only, its options are provided by the app existingFilters.push({ id: todoDueStatusFilter.id, type: todoDueStatusFilter.type, }); } configData[viewConfigKey].config.filters = existingFilters; } // Details View if (!configData[viewConfigKey + "/:id"]) { configData[viewConfigKey + "/:id"] = JSON.parse( JSON.stringify(defaultTodoDetailsView), ); } return configPart; }

Add default view:note/:id NoteDetails config to avoid breaking note details with a default config from AdminModule

defaultTodoDetailsView
Type : object
Default value : { component: "EntityDetails", config: { entityType: Todo.ENTITY_TYPE, panels: [ { title: "Overview", components: [ { title: "", component: "Form", config: { fieldGroups: [ { fields: [ "subject", "deadline", "startDate", "description", "assignedTo", "relatedEntities", "repetitionInterval", "completed", ], }, ], }, }, ], }, ], }, }
defaultTodoListView
Type : object
Default value : { component: "EntityList", config: { entityType: "Todo", columns: [ "deadline", "subject", "assignedTo", "startDate", "relatedEntities", "completed", ], filters: [ { id: "assignedTo", default: PLACEHOLDERS.CURRENT_USER }, { id: "todo-due-status", type: "prebuilt" }, ], defaultSort: { active: "deadline", direction: "asc" }, clickMode: "popup-details", showInactive: true, }, }
todoDueStatusFilter
Type : PrebuiltFilterConfig<Todo>
Default value : { id: "todo-due-status", type: "prebuilt", label: $localize`Tasks due`, options: [ { key: "current", label: $localize`:Filter-option for todos:Currently Active`, filter: { $and: [ TODO_NOT_COMPLETED_FILTER, { $or: [ { startDate: { $exists: false, }, }, { startDate: { $lte: moment().format("YYYY-MM-DD"), $gt: "", }, }, { deadline: { $lte: moment().format("YYYY-MM-DD"), $gt: "", }, }, ], }, ], } as DataFilter<Todo>, }, { key: "overdue", label: $localize`:Filter-option for todos:Overdue`, filter: { $and: [ TODO_NOT_COMPLETED_FILTER, { deadline: { $lte: moment().format("YYYY-MM-DD"), $gt: "" } }, ], } as DataFilter<Todo>, }, { key: "completed", label: $localize`:Filter-option for todos:Completed`, filter: TODO_COMPLETED_FILTER, }, { key: "open", label: $localize`:Filter-option for todos:All Open`, filter: TODO_NOT_COMPLETED_FILTER, }, { key: "any", label: $localize`Any`, filter: {} }, ], singleSelectOnly: true, default: "current", }

Special filter with pre-defined categories of Todo items.

src/app/core/config/config.app-initializer.ts

APP_INITIALIZER_PROPAGATE_CONFIG_UPDATES
Type : unknown
Default value : provideAppInitializer( () => { const configService = inject(ConfigService); const routerService = inject(RouterService); const entityConfigService = inject(EntityConfigService); const router = inject(Router); const destroyRef = inject(DestroyRef); const componentRegistry = inject(ComponentRegistry); // Re-trigger services that depend on the config when something changes configService.configUpdates .pipe(takeUntilDestroyed(destroyRef)) // especially for tests, this ensures cleanup .subscribe(() => { routerService.initRouting(); entityConfigService.setupEntitiesFromConfig(); const url = router.parseUrl(router.url); router.navigateByUrl(url, { skipLocationChange: true }); // Preload all dynamic component chunks in the background for offline availability preloadDynamicComponents(componentRegistry, destroyRef); }); }, )
preloadScheduled
Type : unknown
Default value : false

Preload all components registered in the ComponentRegistry so their JS chunks are cached by the service worker and available offline even before the user has visited every page.

Runs once in an idle callback to avoid blocking the main thread after login.

src/app/features/attendance/model/attendance-status.ts

ATTENDANCE_STATUS_CONFIG_ID
Type : string
Default value : "attendance-status"

the id through which the available attendance status types can be loaded from the ConfigService.

NullAttendanceStatusType
Type : AttendanceStatusType
Default value : { id: "", label: "", shortName: "", countAs: AttendanceLogicalStatus.IGNORE, }

Null object representing an unknown attendance status.

This allows easier handling of attendance status logic because exceptional checks for undefined are not necessary.

src/app/features/attendance/attendance-components.ts

attendanceComponents
Type : ComponentTuple[]
Default value : [ [ "AttendanceManager", () => import("./add-day-attendance/attendance-manager/attendance-manager.component").then( (c) => c.AttendanceManagerComponent, ), ], [ "AddDayAttendance", () => import("./add-day-attendance/roll-call-setup/roll-call-setup.component").then( (c) => c.RollCallSetupComponent, ), ], [ "RollCall", () => import("./add-day-attendance/roll-call/roll-call.component").then( (c) => c.RollCallComponent, ), ], [ "GroupedChildAttendance", () => import("./analysis/grouped-child-attendance/grouped-child-attendance.component").then( (c) => c.GroupedChildAttendanceComponent, ), ], [ "ActivityAttendanceSection", () => import("./analysis/activity-attendance-section/activity-attendance-section.component").then( (c) => c.ActivityAttendanceSectionComponent, ), ], [ "AttendanceWeekDashboard", () => import("./attendance-week-dashboard/attendance-week-dashboard.component").then( (c) => c.AttendanceWeekDashboardComponent, ), ], [ "EditLegacyAttendance", () => import("./deprecated/edit-legacy-attendance.component").then( (c) => c.EditLegacyAttendanceComponent, ), ], [ "EditAttendance", () => import("./edit-attendance/edit-attendance.component").then( (c) => c.EditAttendanceComponent, ), ], [ "DisplayAttendance", () => import("./display-attendance/display-attendance.component").then( (c) => c.DisplayAttendanceComponent, ), ], [ "AttendanceWeekDashboardSettings", () => import("./attendance-week-dashboard/attendance-week-dashboard-settings.component/attendance-week-dashboard-settings.component").then( (c) => c.AttendanceWeekDashboardSettingsComponent, ), ], ]

src/app/features/change-history/change-history.service.ts

AUDIT_RECORD_SUBJECT
Type : string
Default value : "AuditRecord"

CASL subject the audit records are keyed under (see replication-backend #4026).

src/app/core/common-components/entities-table/data-source/available-data-sources.ts

availableDataSources
Type : object
Default value : { "in-memory": InMemoryDataSource, paginated: PaginatedDataSource, }

src/app/core/language/languages.ts

availableLocales
Type : unknown
Default value : new ConfigurableEnum(LOCALE_ENUM_ID, [ { id: "en-US", label: "English (en)" }, { id: "de", label: "Deutsch / German (de)" }, { id: "fr", label: "Français / French (fr)" }, ])

A readonly array of all locales available

LOCALE_ENUM_ID
Type : string
Default value : "locales"

src/app/features/change-history/change-history.types.ts

BASELINE_NOTE
Type : unknown
Default value : $localize`:Change history baseline note:Record state captured when change logging was enabled. Edits made before this point aren't recorded.`

Explanation for the synthetic "initial snapshot" entry, shown both inline in its diff and as the badge tooltip (single source of truth).

OPERATION_TO_ACTION
Type : Record<string, ChangeAction>
Default value : { create: "created", update: "updated", delete: "deleted", baseline: "baseline", }

Maps the backend audit operation to the displayed ChangeAction.

src/app/core/common-components/basic-autocomplete/basic-autocomplete.component.ts

BASIC_AUTOCOMPLETE_COMPONENT_IMPORTS
Type : []
Default value : [ ReactiveFormsModule, MatInputModule, MatAutocompleteModule, MatCheckboxModule, NgTemplateOutlet, MatChipInput, MatChipGrid, MatChipRow, FaDynamicIconComponent, MatTooltip, MatChipRemove, DragDropModule, CdkVirtualScrollViewport, CdkVirtualForOf, CdkFixedSizeVirtualScroll, KeepPanelOpenOnSelectDirective, ]

src/bootstrap-pwa-install.ts

canInstallDirectly
Type : Promise | undefined

Resolves once/if it is possible to directly install the app

deferredInstallPrompt
Type : BeforeInstallPromptEvent | undefined

The deferred beforeinstallprompt event, to be triggered on user request

installPromptListener
Type : unknown | undefined

The registered listener, kept so resetPWAInstallListener can remove it again

src/app/core/logging/logging.service.ts

CAUSE_GROUPED_ERROR_TYPES
Type : miscellaneous
Default value : [ "DatabaseException", "SyncStalledError", "ConfigLoadError", "PermissionRulesLoadError", "SiteSettingsLoadError", "RegistryLookupError", "RegistryDuplicateError", ]

Our own error classes that describe what failed precisely enough that all their occurrences belong into a single issue in remote monitoring, no matter which component, route or async call site ran into them.

For these, Sentry's default grouping by stack trace actively hurts: they are thrown from one central place, while the stack differs per caller and even per build (releases without source maps report minified frames). One problem then scatters across a dozen issues that each have to be triaged separately, and archiving one of them does not silence the others.

Only add error types whose name and message already identify the problem on their own, so that the stack adds nothing but noise. Generic errors (Error, TypeError, ...) must keep the default grouping - for those the stack trace is the only thing telling two unrelated bugs apart.

CONFLICT_MESSAGE
Type : string
Default value : "document update conflict"

How PouchDB words a rejected write, after fingerprintKey normalization.

FALLBACK_EXCEPTION_TYPE
Type : string
Default value : "Error"

Placeholder type for an exception reported without one.

Sentry builds an issue title from the reported exception's type and message, and lists an issue whose exception carries no type as <unknown> - which says nothing at all in a list of issues, and hides the message that would have. The generic name is no loss: it is what an Error subclass reports anyway unless it sets name explicitly (see CAUSE_GROUPED_ERROR_TYPES).

Logging
Type : miscellaneous
Default value : new LoggingService()
MAX_REPEATED_SENTRY_EVENTS
Type : number
Default value : 5

Maximum number of times an identical event is sent to remote logging within one app session (page load). Guards against error loops (e.g. an error thrown on every change detection cycle) flooding remote monitoring with thousands of duplicate events.

MAX_REPORTED_MESSAGE_LENGTH
Type : number
Default value : 300

How much of an error message is kept as the reported one (see reportNormalized). Generous enough for any message written to be read, and a backstop against the ones that turn out to be a serialized document or a web page.

NETWORK_FAILURE
Type : string
Default value : "network failure"

Placeholder for a connectivity failure, which every browser words differently ("Failed to fetch" / "Load failed" / ...) while describing one problem.

Substituted wherever an error message is used as a grouping key or shown as the cause of another error, so that a mix of browsers neither splits an issue nor makes its title flip-flop between its events.

sentryEventCounts
Type : unknown
Default value : new Map<string, number>()
VOLATILE_VALUE_PATTERNS
Type : unknown[]
Default value : [ // a response body quoted into an error message (a proxy failure, an error // page served by the reverse proxy): its content varies per request and can // be a whole HTML document, which as an issue title hides every other row [/ with body ["'][\s\S]*$/i, ""], [/https?:\/\/\S+/gi, "<url>"], [ /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, "<uuid>", ], [/\b\d+-[0-9a-f]{32}\b/gi, "<rev>"], // legacy entity ids that embed a username (e.g. `User:some.person`); the // uuid-based ones are already masked above. Requires a non-space directly // after the colon, so that an error prefix like "TypeError: ..." is kept. [/\b[A-Z][A-Za-z]{2,}:[A-Za-z0-9._<>-]+/g, "<entityId>"], [/\d+/g, "<n>"], ]

Data that varies between occurrences of the same problem and therefore has to be masked before an error message can be used as a grouping key. Order matters: the more specific patterns have to run before the plain number.

src/app/child-dev-project/children/demo-data-generators/fixtures/centers.ts

centersUnique
Type : ConfigurableEnumValue[]
Default value : enums.find( (e) => e._id === "ConfigurableEnum:center", ).values
centersWithProbability
Type : unknown
Default value : [0, 0, 1, 2].map((i) => centersUnique[i])

src/app/child-dev-project/children/children-components.ts

childrenComponents
Type : ComponentTuple[]
Default value : [ [ "DisplayParticipantsCount", () => import("./display-participants-count/display-participants-count.component").then( (c) => c.DisplayParticipantsCountComponent, ), ], ]

src/app/utils/connectivity-error.ts

CHUNK_LOAD_ERROR_PATTERNS
Type : []
Default value : [ // Chrome/Edge: "Failed to fetch dynamically imported module: <url>" // Firefox: "error loading dynamically imported module: <url>" "dynamically imported module", "Importing a module script failed", // Safari ]

Wordings for a lazily loaded application chunk that could not be fetched.

These are requests that did not arrive, like any other connectivity failure: the device is offline, or a new deployment replaced the chunk that the still-running app asks for. Which of the two it was is not visible from the error, and neither is actionable per chunk - so they belong in the shared network issue rather than in one issue per chunk URL and browser wording.

CONNECTIVITY_ERROR_NAMES
Type : []
Default value : ["TimeoutError", "AbortError"]

Error names that browsers use for requests that were cut off before completing, rather than answered with an error.

CONNECTIVITY_ERROR_PATTERNS
Type : []
Default value : [ "Failed to fetch", // Chrome (also matches DatabaseException "Failed to fetch from DB") "NetworkError", // Firefox ("NetworkError when attempting to fetch resource") "Load failed", // Safari "Network request failed", "network timeout", "0 Unknown Error", // Angular HttpErrorResponse for a request that never reached the server ...CHUNK_LOAD_ERROR_PATTERNS, ]

Common network/connectivity error patterns shared across the application. These indicate transient failures (offline, DNS, proxy issues) rather than application-level errors.

CONNECTIVITY_ERROR_STATUS
Type : []
Default value : [0, 502, 503, 504]

HTTP statuses of a request that never reached the application's backend: 0 for one that got no response at all, the others reported by an infrastructure component in front of it.

src/app/features/location/geo-location.ts

CITY_FIELDS
Type : unknown
Default value : [ "city", "town", "village", "suburb", "municipality", ] as const

Fields OpenStreetMap may use for the place a person would name as their town, ordered from the most specific to the widest area. Many places have no city at all: an address in a Dublin suburb, for example, only carries suburb.

src/app/features/attendance/attendance-permission.guard.ts

COMPONENT_PERMISSIONS
Type : Record<string, { configKey: "activityTypes" | "eventTypes"; operation: EntityActionPermission }>
Default value : { AttendanceManager: { configKey: "activityTypes", operation: "read", }, AddDayAttendance: { configKey: "eventTypes", operation: "create" }, RollCall: { configKey: "eventTypes", operation: "create" }, }

Maps component name to the service signal property and required operation for permission checks.

src/app/dynamic-components.ts

componentRegistry
Type : unknown
Default value : new ComponentRegistry()

src/app/core/config/dynamic-routing/route-paths.ts

CONFIG_ENTITY_ROUTE_PREFIX
Type : string
Default value : "c"

Stable URL prefix used for entity routes loaded from runtime config.

src/bootstrap-environment.ts

CONFIG_JSON_MAX_RELOAD_ATTEMPTS
Type : number
Default value : 1
CONFIG_JSON_RELOAD_ATTEMPTS_KEY
Type : string
Default value : "config_json_reload_attempts"

sessionStorage key tracking how many times we've auto-reloaded due to a failure loading config.json, so a persistent failure (e.g. offline) doesn't reload-loop and flood error monitoring.

src/app/core/admin/setup-wizard/setup-wizard-config.ts

CONFIG_SETUP_WIZARD_ID
Type : string
Default value : "Config:SetupWizard"

src/app/core/config/config-migrations.ts

configMigrations
Type : ConfigMigration[]
Default value : [ migrateEntityDetailsInputEntityType, migrateEntityArrayDatatype, migrateEntitySchemaDefaultValue, migrateChildrenListConfig, migrateHistoricalDataComponent, migratePhotoDatatype, migratePercentageDatatype, migrateEntityBlock, migrateGroupByConfig, migrateLegacyIdFilters, migrateDefaultValue, migrateInheritedFieldConfig, migrateUserEntityAndPanels, migrateComponentEntityTypeDefaults, removeOutdatedTodoViews, migrateChildSchoolOverviewComponent, migrateEditDescriptionOnly, migrateEditAttendanceComponent, migrateNotesManagerComponent, removeConfigRoutesMigratedToFixedFeatures, migrateAttendanceRecurringActivityRoute, removeExportConfig, migrateIsActiveReportQueries, removeIsActiveFilters, migrateTodoDueStatusFilter, migrateShortcutDashboardLinks, migrateNavigationMenuEntityLinks, // must run last to see all default-added view configs ]

All temporary config migrations that fix legacy data formats. Applied by both ConfigService (Angular app) and the admin CLI. Order matters: earlier migrations may produce output consumed by later ones.

FILTER_CONFIG_KEYS
Type : []
Default value : ["filter", "prefilter"]

Config keys whose value is a filter object (MongoDB-style query) defined by admins, e.g. the fixed filter of a RelatedEntities view, the filter of a prebuilt filter option or the prefilter of a matching view's side.

FILTER_LOGICAL_OPERATORS
Type : []
Default value : ["$and", "$or", "$nor"]

Filter operators whose value is a list of nested filter conditions.

migrateAttendanceRecurringActivityRoute
Type : ConfigMigration
Default value : ( key, configPart, ) => { if ( key !== "" || !configPart?.data || typeof configPart.data !== "object" || Array.isArray(configPart.data) ) { return configPart; } const data = configPart.data; const OLD_LIST = "view:attendance/recurring-activity"; const OLD_DETAILS = "view:attendance/recurring-activity/:id"; const NEW_LIST = "view:recurring-activity"; const NEW_DETAILS = "view:recurring-activity/:id"; if (data[OLD_LIST] && !data[NEW_LIST]) { data[NEW_LIST] = data[OLD_LIST]; delete data[OLD_LIST]; } else { delete data[OLD_LIST]; } if (data[OLD_DETAILS] && !data[NEW_DETAILS]) { data[NEW_DETAILS] = data[OLD_DETAILS]; delete data[OLD_DETAILS]; } else { delete data[OLD_DETAILS]; } if (Array.isArray(data?.navigationMenu?.items)) { data.navigationMenu.items = rewriteNavMenuLinks( data.navigationMenu.items, "/attendance/recurring-activity", "/recurring-activity", ); } if ( data["entity:RecurringActivity"]?.route === "attendance/recurring-activity" ) { data["entity:RecurringActivity"].route = "recurring-activity"; } return configPart; }
migrateChildrenListConfig
Type : ConfigMigration
Default value : (key, configPart) => { if ( typeof configPart !== "object" || configPart?.["component"] !== "ChildrenList" ) { return configPart; } configPart["component"] = "EntityList"; configPart["config"] = configPart["config"] ?? {}; configPart["config"]["entityType"] = "Child"; configPart["config"]["loaderMethod"] = "ChildrenService"; return configPart; }
migrateChildSchoolOverviewComponent
Type : ConfigMigration
Default value : ( key, configPart, ) => { const deprecatedComponents = [ "ChildSchoolOverview", "PreviousSchools", "ChildrenOverview", ]; if (typeof configPart === "object" && Array.isArray(configPart?.panels)) { const entityType = configPart?.entityType; const isChildDetails = typeof entityType === "string" && entityType.toLowerCase() === "child"; configPart.panels.forEach((panel) => { panel.components?.forEach((component, index) => { if ( typeof component === "object" && deprecatedComponents.includes(component.component) ) { const newConfig = Object.assign( {}, isChildDetails ? relatedEntitiesForChild : relatedEntitiesForSchool, component.config, ); panel.components[index] = { component: "RelatedEntities", config: newConfig, }; component.config.entityType = "ChildSchoolRelation"; component.config.loaderMethod = "ChildrenServiceQueryRelations"; } }); }); } return configPart; }
migrateComponentEntityTypeDefaults
Type : ConfigMigration
Default value : ( key, configPart, ) => { if (typeof configPart !== "object" || !configPart?.component) { return configPart; } if (!configPart.config) { configPart.config = {}; } const defaults = RELATED_ENTITIES_DEFAULT_CONFIGS[configPart.component]; if (defaults) { configPart.config.entityType = defaults.entityType; if ( !Array.isArray(configPart.config.columns) || configPart.config.columns.length === 0 ) { configPart.config.columns = defaults.columns; } } return configPart; }
migrateDefaultValue
Type : ConfigMigration
Default value : (key, configPart) => { if (key !== "defaultValue") { return configPart; } if (configPart?.mode === "inherited") { configPart.mode = "inherited-from-referenced-entity"; } if (!configPart.config) { configPart.config = {}; if (configPart.value) { configPart.config.value = configPart.value; delete configPart.value; } if (configPart.localAttribute) { configPart.config.localAttribute = configPart.localAttribute; delete configPart.localAttribute; } if (configPart.field) { configPart.config.field = configPart.field; delete configPart.field; } } return configPart; }
migrateEditAttendanceComponent
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.editComponent !== "EditAttendance") { return configPart; } configPart.editComponent = "EditLegacyAttendance"; return configPart; }
migrateEditDescriptionOnly
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.editComponent !== "EditDescriptionOnly") { return configPart; } configPart.viewComponent = "DisplayDescriptionOnly"; delete configPart.editComponent; return configPart; }
migrateEntityArrayDatatype
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart === "DisplayEntityArray") { return "DisplayEntity"; } if (!configPart?.hasOwnProperty("dataType")) { return configPart; } const config: EntitySchemaField = configPart; if (config.dataType === "entity-array") { config.dataType = "entity"; // inlined: EntityDatatype.dataType config.isArray = true; } if (config.dataType === "array") { config.dataType = config["innerDataType"]; delete config["innerDataType"]; config.isArray = true; } if (config.dataType === "configurable-enum" && config["innerDataType"]) { config.additional = config["innerDataType"]; delete config["innerDataType"]; } return configPart; }
migrateEntityBlock
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.["blockComponent"] === "ChildBlock") { delete configPart["blockComponent"]; configPart["toBlockDetailsAttributes"] = { title: "name", image: "photo", fields: ["phone", "schoolId", "schoolClass"], }; return configPart; } if (key === "viewComponent" && configPart === "ChildBlock") { return "EntityBlock"; } return configPart; }
migrateEntityDetailsInputEntityType
Type : ConfigMigration
Default value : ( key, configPart, ) => { if (key !== "config") { return configPart; } if (configPart["entity"]) { configPart["entityType"] = configPart["entity"]; delete configPart["entity"]; } return configPart; }
migrateEntitySchemaDefaultValue
Type : ConfigMigration
Default value : ( key: string, configPart: any, ): any => { if (key !== "defaultValue") { return configPart; } if (typeof configPart == "object") { return configPart; } let placeholderValue: string | undefined = Object.values(PLACEHOLDERS).find( (value) => value === configPart, ); if (placeholderValue) { return { mode: "dynamic", value: placeholderValue, } as DefaultValueConfig; } return { mode: "static", value: configPart, } as DefaultValueConfig; }
migrateGroupByConfig
Type : ConfigMigration
Default value : (key, configPart) => { if ( configPart?.component === "EntityCountDashboard" && typeof configPart?.config?.groupBy === "string" ) { configPart.config.groupBy = [configPart.config.groupBy]; return configPart; } return configPart; }
migrateHistoricalDataComponent
Type : ConfigMigration
Default value : (key, configPart) => { if ( typeof configPart !== "object" || configPart?.["component"] !== "HistoricalDataComponent" ) { return configPart; } configPart["component"] = "RelatedEntities"; configPart["config"] = configPart["config"] ?? {}; if (Array.isArray(configPart["config"])) { configPart["config"] = { columns: configPart["config"] }; } configPart["config"]["entityType"] = "HistoricalEntityData"; configPart["config"]["loaderMethod"] = "HistoricalDataService"; // inlined: LoaderMethod.HistoricalDataService return configPart; }
migrateIsActiveReportQueries
Type : ConfigMigration
Default value : (key, configPart) => { if (key !== "query") { return configPart; } return migrateIsActiveQuerySelection(configPart); }

Entities do not provide a calculated "isActive" property anymore. Report queries selecting on it have to use the equivalent query helpers instead.

migrateLegacyIdFilters
Type : ConfigMigration
Default value : (key, configPart) => { if (!configPart || typeof configPart !== "object") { return configPart; } const orConditions = (configPart as LegacyOrFilterConfig)["$or"]; if (!Array.isArray(orConditions)) { return configPart; } const migratedConditions = orConditions.map((orCondition) => { if (!orCondition || typeof orCondition !== "object") { return orCondition; } let hasLegacyIdKey = false; const normalizedEntries = Object.entries(orCondition).map( ([key, value]) => { if (key.endsWith(".id")) { hasLegacyIdKey = true; return [key.slice(0, -3), value] as const; } return [key, value] as const; }, ); return hasLegacyIdKey ? (Object.fromEntries(normalizedEntries) as OrFilterCondition) : orCondition; }); configPart["$or"] = migratedConditions; return configPart; }
migrateNavigationMenuEntityLinks
Type : ConfigMigration
Default value : ( key, configPart, ) => { if ( key !== "" || !configPart?.data || typeof configPart.data !== "object" || Array.isArray(configPart.data) || !Array.isArray(configPart.data?.navigationMenu?.items) ) { return configPart; } configPart.data.navigationMenu.items = migrateNavMenuItems( configPart.data.navigationMenu.items, configPart.data, ); return configPart; }

Migrate navigationMenu items that use a hardcoded entity route link to the entityType format.

migrateNotesManagerComponent
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.component !== "NotesManager") { return configPart; } configPart.component = "EntityList"; if (!configPart.config) { configPart.config = {}; } configPart.config.entityType = "Note"; configPart.config.clickMode = "popup-details"; delete configPart.config.includeEventNotes; delete configPart.config.showEventNotesToggle; return configPart; }
migratePercentageDatatype
Type : ConfigMigration
Default value : (key, configPart) => { if ( configPart?.dataType === "number" && configPart?.viewComponent === "DisplayPercentage" ) { configPart.dataType = "percentage"; delete configPart.viewComponent; delete configPart.editComponent; } return configPart; }
migratePhotoDatatype
Type : ConfigMigration
Default value : (key, configPart) => { if ( configPart?.dataType === "file" && configPart?.editComponent === "EditPhoto" ) { configPart.dataType = "photo"; delete configPart.editComponent; } return configPart; }
migrateShortcutDashboardLinks
Type : ConfigMigration
Default value : ( key, configPart, ) => { if ( key !== "" || !configPart?.data || typeof configPart.data !== "object" || Array.isArray(configPart.data) ) { return configPart; } const data = configPart.data; const entityBasePaths = buildEntityBasePaths(data); if (entityBasePaths.size === 0) return configPart; for (const dataKey of Object.keys(data)) { if (!dataKey.startsWith(PREFIX_VIEW_CONFIG)) continue; const viewConfig = data[dataKey]; if (!Array.isArray(viewConfig?.config?.widgets)) continue; for (const widget of viewConfig.config.widgets) { if ( widget.component === "ShortcutDashboard" && Array.isArray(widget.config?.shortcuts) ) { widget.config.shortcuts = widget.config.shortcuts.map((shortcut: any) => migrateShortcutItem(shortcut, entityBasePaths), ); } } } return configPart; }

Migrate ShortcutDashboard widget link values that point to entity routes to use the runtime /c/ prefix.

Extracted here (rather than kept only in ConfigService) so the CLI's latest-config-formats migration can also persist this fix to production config documents, not just apply it transiently in the running app.

migrateTodoDueStatusFilter
Type : ConfigMigration
Default value : (key, configPart) => { if (configPart?.id !== "todo-due-status" || !configPart?.options) { return configPart; } delete configPart.options; return configPart; }

Older configs contain a full copy of the prebuilt "tasks due" filter, whose options selected on calculated properties that do not exist anymore. Drop the stored options so the definition provided by the app is used.

migrateUserEntityAndPanels
Type : ConfigMigration
Default value : (key, configPart) => { if (key === "entity:User") { configPart.enableUserAccounts = true; } if (key === "view:user/:id") { configPart.config.panels = (configPart.config.panels || []).filter( (panel) => !panel.components?.some( (c: PanelComponent) => c.component === "UserSecurity", ), ); } return configPart; }
relatedEntitiesForChild
Type : object
Default value : { entityType: "ChildSchoolRelation", columns: [ { id: "start", visibleFrom: "md" }, { id: "end", visibleFrom: "md" }, { id: "schoolId" }, { id: "schoolClass" }, { id: "result" }, ], loaderMethod: "ChildrenServiceQueryRelations", showInactive: true, }
relatedEntitiesForSchool
Type : object
Default value : { entityType: "ChildSchoolRelation", columns: [ { id: "childId" }, { id: "start", visibleFrom: "md" }, { id: "end", visibleFrom: "md" }, { id: "schoolClass" }, { id: "result" }, ], loaderMethod: "ChildrenServiceQueryRelations", }
removeConfigRoutesMigratedToFixedFeatures
Type : ConfigMigration
Default value : ( key, configPart, ) => { if ( key !== "" || !configPart?.data || typeof configPart.data !== "object" || Array.isArray(configPart.data) ) { return configPart; } delete configPart.data["view:import"]; delete configPart.data["view:review-duplicates"]; return configPart; }
removeExportConfig
Type : ConfigMigration
Default value : (key, configPart) => { if ( configPart && typeof configPart === "object" && !Array.isArray(configPart) && "exportConfig" in configPart ) { delete configPart.exportConfig; } return configPart; }
removeIsActiveFilters
Type : ConfigMigration
Default value : (key, configPart) => { if (!FILTER_CONFIG_KEYS.includes(key)) { return configPart; } return removeIsActiveCondition(configPart); }

Entities do not provide a calculated "isActive" property anymore, so a configured filter selecting on it cannot match anything.

isActive: true is simply dropped: lists exclude archived records by default now (see NOT_ARCHIVED_FILTER), which is exactly what the condition used to express.

isActive: false (i.e. archived records only) is dropped as well. It has no equivalent in a configured filter anymore, because the default not-archived condition is combined with $and and any explicit "archived" condition would make such a filter match no record at all. Users can include archived records through the list's "show inactive" toggle instead.

removeOutdatedTodoViews
Type : ConfigMigration
Default value : (key, configPart) => { if ( configPart?.component === "TodoList" || configPart?.component === "TodoDetails" ) { return undefined; } return configPart; }

src/app/features/conflict-resolution/auto-resolution/conflict-resolution-strategy.ts

CONFLICT_RESOLUTION_STRATEGY
Type : unknown
Default value : new InjectionToken< ConflictResolutionStrategy[] >("ConflictResolutionStrategy")

Use this token to provide (and thereby register) custom implementations of ConflictResolutionStrategy.

{ provide: CONFLICT_RESOLUTION_STRATEGY, useClass: MyConflictResolutionStrategy, multi: true }

see ConflictResolutionModule

src/app/features/conflict-resolution/conflict-resolution-components.ts

conflictResolutionComponents
Type : ComponentTuple[]
Default value : [ [ "ConflictResolution", () => import("./conflict-resolution-list/conflict-resolution-list.component").then( (c) => c.ConflictResolutionListComponent, ), ], ]

src/app/core/core-components.ts

coreComponents
Type : ComponentTuple[]
Default value : [ [ "DisplayConfigurableEnum", () => import("./basic-datatypes/configurable-enum/display-configurable-enum/display-configurable-enum.component").then( (c) => c.DisplayConfigurableEnumComponent, ), ], [ "EditConfigurableEnum", () => import("./basic-datatypes/configurable-enum/edit-configurable-enum/edit-configurable-enum.component").then( (c) => c.EditConfigurableEnumComponent, ), ], [ "Form", () => import("./entity-details/form/form.component").then( (c) => c.FormComponent, ), ], [ "EditEntity", () => import("./basic-datatypes/entity/edit-entity/edit-entity.component").then( (c) => c.EditEntityComponent, ), ], [ "DisplayEntity", () => import("./basic-datatypes/entity/display-entity/display-entity.component").then( (c) => c.DisplayEntityComponent, ), ], [ "EntityBlock", () => import("./basic-datatypes/entity/entity-block/entity-block.component").then( (c) => c.EntityBlockComponent, ), ], [ "EditTextWithAutocomplete", () => import("./common-components/edit-text-with-autocomplete/edit-text-with-autocomplete.component").then( (c) => c.EditTextWithAutocompleteComponent, ), ], [ "EditAge", () => import("./basic-datatypes/date-with-age/edit-age/edit-age.component").then( (c) => c.EditAgeComponent, ), ], [ "EditText", () => import("./basic-datatypes/string/edit-text/edit-text.component").then( (c) => c.EditTextComponent, ), ], [ "EditBoolean", () => import("./basic-datatypes/boolean/edit-boolean/edit-boolean.component").then( (c) => c.EditBooleanComponent, ), ], [ "EditDate", () => import("./basic-datatypes/date/edit-date/edit-date.component").then( (c) => c.EditDateComponent, ), ], [ "EditMonth", () => import("./basic-datatypes/month/edit-month/edit-month.component").then( (c) => c.EditMonthComponent, ), ], [ "EditLongText", () => import("./basic-datatypes/string/edit-long-text/edit-long-text.component").then( (c) => c.EditLongTextComponent, ), ], [ "EditPhoto", () => import("../features/file/edit-photo/edit-photo.component").then( (c) => c.EditPhotoComponent, ), ], [ "EditNumber", () => import("./basic-datatypes/number/edit-number/edit-number.component").then( (c) => c.EditNumberComponent, ), ], [ "DisplayDescriptionOnly", () => import("./common-components/description-only/display-description-only/display-description-only.component").then( (c) => c.DisplayDescriptionOnlyComponent, ), ], [ "DisplayCheckmark", () => import("./basic-datatypes/boolean/display-checkmark/display-checkmark.component").then( (c) => c.DisplayCheckmarkComponent, ), ], [ "DisplayText", () => import("./basic-datatypes/string/display-text/display-text.component").then( (c) => c.DisplayTextComponent, ), ], [ "DisplayLongText", () => import("./basic-datatypes/string/display-long-text/display-long-text.component").then( (c) => c.DisplayLongTextComponent, ), ], [ "DisplayDate", () => import("./basic-datatypes/date/display-date/display-date.component").then( (c) => c.DisplayDateComponent, ), ], [ "DisplayEntityType", () => import("./entity/display-entity-type/display-entity-type.component").then( (c) => c.DisplayEntityTypeComponent, ), ], [ "DisplayMonth", () => import("./basic-datatypes/month/display-month/display-month.component").then( (c) => c.DisplayMonthComponent, ), ], [ "ReadonlyFunction", () => import("./common-components/display-readonly-function/readonly-function.component").then( (c) => c.ReadonlyFunctionComponent, ), ], [ "DisplayPercentage", () => import("./basic-datatypes/number/display-percentage/display-percentage.component").then( (c) => c.DisplayPercentageComponent, ), ], [ "DisplayDynamicPercentage", () => import("./basic-datatypes/number/display-dynamic-percentage/display-calculated-value.component").then( (c) => c.DisplayCalculatedValueComponent, ), ], [ "DisplayCalculatedValue", () => import("./basic-datatypes/number/display-dynamic-percentage/display-calculated-value.component").then( (c) => c.DisplayCalculatedValueComponent, ), ], [ "DisplayUnit", () => import("./basic-datatypes/number/display-unit/display-unit.component").then( (c) => c.DisplayUnitComponent, ), ], [ "DisplayAge", () => import("./basic-datatypes/date-with-age/display-age/display-age.component").then( (c) => c.DisplayAgeComponent, ), ], [ "UserSecurity", () => import("./user/entity-user/entity-user.component").then( (c) => c.EntityUserComponent, ), ], [ "Dashboard", () => import("./dashboard/dashboard/dashboard.component").then( (c) => c.DashboardComponent, ), ], [ "EntityList", () => import("./entity-list/entity-list/entity-list.component").then( (c) => c.EntityListComponent, ), ], [ "EntityDetails", () => import("./entity-details/entity-details/entity-details.component").then( (c) => c.EntityDetailsComponent, ), ], [ "RelatedEntities", () => import("./entity-details/related-entities/related-entities.component").then( (c) => c.RelatedEntitiesComponent, ), ], [ "RelatedTimePeriodEntities", () => import("./entity-details/related-time-period-entities/related-time-period-entities.component").then( (c) => c.RelatedTimePeriodEntitiesComponent, ), ], [ "RelatedEntitiesWithSummary", () => import("./entity-details/related-entities-with-summary/related-entities-with-summary.component").then( (c) => c.RelatedEntitiesWithSummaryComponent, ), ], [ "EditEntityType", () => import("./entity/edit-entity-type/edit-entity-type.component").then( (c) => c.EditEntityTypeComponent, ), ], [ "EditUrl", () => import("./basic-datatypes/string/edit-url/edit-url.component").then( (c) => c.EditUrlComponent, ), ], [ "DisplayUrl", () => import("./basic-datatypes/string/display-url/display-url.component").then( (c) => c.DisplayUrlComponent, ), ], [ "EditEmail", () => import("./basic-datatypes/string/edit-email/edit-email.component").then( (c) => c.EditEmailComponent, ), ], [ "DisplayEmail", () => import("./basic-datatypes/string/display-email/display-email.component").then( (c) => c.DisplayEmailComponent, ), ], [ "EditDateFormat", () => import("./basic-datatypes/date/edit-date-format/edit-date-format.component").then( (c) => c.EditDateFormatComponent, ), ], [ "EditColor", () => import("./common-components/color-input/color-input.component").then( (c) => c.ColorInputComponent, ), ], [ "EditJson", () => import("./admin/json-editor/edit-json/edit-json.component").then( (c) => c.EditJsonComponent, ), ], ]

src/app/core/entity-details/related-time-period-entities/related-time-period-entities.component.ts

CURRENTLY_ACTIVE_COLOR
Type : string
Default value : "#90ee9040"

highlight color for the entry that covers the current date

currentlyActiveIndicator
Type : FormFieldConfig
Default value : { id: "currentlyActive", label: $localize`:Label for the currently active status|e.g. Currently active:Currently`, viewComponent: "ReadonlyFunction", hideFromTable: true, description: $localize`:Tooltip for the status of currently active or not:Only added to linked record if active. Change the start or end date to modify this status.`, additional: (csr: ChildSchoolRelation) => csr.isActiveAt(new Date()) ? $localize`:Indication for the currently active status of an entry:active` : $localize`:Indication for the currently inactive status of an entry:not active`, }

src/app/utils/custom-number-validators.ts

CustomNumberValidators
Type : { isNumber: ValidatorFn }
Default value : { /** * Angular Validator to verify value is a valid number. */ isNumber: (control: AbstractControl) => { if (control.value && Number.isNaN(Number(control.value))) { return { isNumber: "invalid" }; } else { return null; } }, }

Container for custom Angular Validator functions.

src/app/core/language/date-adapter-with-formatting.ts

DATE_FORMATS
Type : MatDateFormats
Default value : { // in addition to the customDate pipe // we need to add dateInput and override the method because we are not using DatePipe here, we are using moment.js // and all date picker inputs are using moment.js, and this will ensure that dates are always displayed in our default format. parse: { get dateInput() { return datepickerFormat(); }, }, display: { ...MAT_NATIVE_DATE_FORMATS.display, get dateInput() { return datepickerFormat(); }, }, }

Extend MAT_NATIVE_DATE_FORMATS to also support parsing. dateInput uses a getter so it always reflects the current global date format from date.static.

src/app/core/database/indexeddb-migration.service.ts

DB_MIGRATED_PREFIX
Type : string
Default value : "DB_MIGRATED_"

src/app/core/language/language-statics.ts

DEFAULT_LANGUAGE
Type : string
Default value : "en-US"
LANGUAGE_LOCAL_STORAGE_KEY
Type : string
Default value : "locale"

src/app/core/permissions/reserved-roles.ts

DEFAULT_ROLE
Type : ReservedRoleInfo
Default value : { key: DEFAULT_SECTION_KEY, label: $localize`:Reserved role name of the "_default" role:Default`, appliesTo: $localize`applies to any logged-in user, in addition to their roles`, description: $localize`Base permissions that apply to every logged-in user, combined with their other roles`, icon: "lock", }

The "_default" role, whose permissions every logged-in user has in addition to the permissions of their own roles.

PUBLIC_ROLE
Type : ReservedRoleInfo
Default value : { key: PUBLIC_SECTION_KEY, label: $localize`:Reserved role name of the "_public" role:Public`, appliesTo: $localize`applies to visitors who are not logged in`, description: $localize`Permissions that apply before login (e.g. public registration forms)`, icon: "globe", }

The "_public" role, whose permissions apply to visitors before login.

RESERVED_ROLES
Type : ReservedRoleInfo[]
Default value : [DEFAULT_ROLE, PUBLIC_ROLE]

The reserved roles with their user-facing name and description, so that all places explaining them to the user (roles overview, permission matrix, permission dialogs) use the same wording.

Ordered as they should be listed to the user.

src/app/core/config/default-config/default-attendance-status-types.ts

defaultAttendanceStatusTypes
Type : unknown
Default value : enumJson.values as AttendanceStatusType[]

src/app/core/basic-datatypes/date/date-range-filter/date-range-filter-panel/date-range-filter-panel.component.ts

defaultDateFilters
Type : DateRangeFilterConfigOption[]
Default value : [ { label: $localize`:Filter label:Today`, }, { startOffsets: [{ amount: 0, unit: "weeks" }], endOffsets: [{ amount: 0, unit: "weeks" }], label: $localize`:Filter label:This week`, }, { startOffsets: [{ amount: -1, unit: "weeks" }], label: $localize`:Filter label:Since last week`, }, { startOffsets: [{ amount: 0, unit: "months" }], endOffsets: [{ amount: 0, unit: "months" }], label: $localize`:Filter label:This month`, }, { startOffsets: [{ amount: -1, unit: "months" }], endOffsets: [{ amount: -1, unit: "months" }], label: $localize`:Filter label:Last month`, }, ]

src/app/core/config/default-config/default-interaction-types.ts

defaultInteractionTypes
Type : unknown
Default value : enums.find( (e) => e._id === "ConfigurableEnum:" + INTERACTION_TYPE_CONFIG_ID, ).values as InteractionType[]

src/app/features/reporting/reporting/select-report/select-report.component.ts

defaultReportDateFilters
Type : DateRangeFilterConfigOption[]
Default value : [ { startOffsets: [{ amount: 0, unit: "months" }], endOffsets: [{ amount: 0, unit: "months" }], label: $localize`:Filter label: Current month`, }, { startOffsets: [{ amount: -1, unit: "months" }], endOffsets: [{ amount: -1, unit: "months" }], label: $localize`:Filter label: Last month`, }, { startOffsets: [{ amount: 0, unit: "quarter" }], endOffsets: [{ amount: 0, unit: "quarter" }], label: $localize`:Filter label: Current quarter`, }, { startOffsets: [{ amount: -1, unit: "quarters" }], endOffsets: [{ amount: -1, unit: "quarters" }], label: $localize`:Filter label: Last quarter`, }, { startOffsets: [{ amount: 0, unit: "years" }], endOffsets: [{ amount: 0, unit: "years" }], label: $localize`:Filter label: Current year`, }, { startOffsets: [{ amount: -1, unit: "years" }], endOffsets: [{ amount: -1, unit: "years" }], label: $localize`:Filter label: Last year`, }, ]

src/app/features/public-form/edit-prefilled-values/edit-prefilled-values.component.ts

defaultValueCompleteValidator
Type : ValidatorFn
Default value : ( control: AbstractControl, ): ValidationErrors | null => { const val: DefaultValueConfig = control.value; if (!val) { return { incompleteDefaultValue: true }; } if (val.mode && !val.config) { return { incompleteDefaultValue: true }; } if ( val.config && typeof val.config === "object" && "value" in val.config && (val.config as { value: unknown }).value == null ) { return { incompleteDefaultValue: true }; } return null; }

src/app/core/default-values/standard-default-value-strategies.ts

defaultValueStrategyProviders
Type : []
Default value : [ { provide: DefaultValueStrategy, useClass: StaticDefaultValueService, multi: true, }, { provide: DefaultValueStrategy, useClass: DynamicPlaceholderValueService, multi: true, }, { provide: DefaultValueStrategy, useClass: InheritedValueService, multi: true, }, ]

Standard default-value strategies that are used in the application. Add further providers to your modules or the AppModule to extend.

src/app/core/common-components/confirmation-dialog/confirmation-dialog/confirmation-dialog.component.ts

DELETE_CONFIRMATION_KEYWORD
Type : miscellaneous
Default value : $localize`:Keyword to be typed by the user to confirm deleting data:delete`

The keyword a user has to type to confirm an action that deletes data irreversibly.

OkButton
Type : ConfirmationDialogButton[]
Default value : [ { text: $localize`:Confirmation dialog OK:OK`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: true, }, ]
YesNoButtons
Type : ConfirmationDialogButton[]
Default value : [ { text: $localize`:Confirmation dialog Yes:Yes`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: true, }, { text: $localize`:Confirmation dialog No:No`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: false, }, ]
YesNoCancelButtons
Type : ConfirmationDialogButton[]
Default value : [ { text: $localize`:Confirmation dialog Yes:Yes`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: true, }, { text: $localize`:Confirmation dialog No:No`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: false, }, { text: $localize`:Confirmation dialog Cancel:Cancel`, click() { // Intentionally blank // To react to emissions from this button, use the `MatDialogRef.beforeClosed()` hook }, dialogResult: undefined, }, ]

src/app/core/demo-data/demo-data.module.ts

demoDataGeneratorProviders
Type : []
Default value : [ ...DemoUserGeneratorService.provider(), ...DemoChildGenerator.provider({ count: 120 }), ...DemoSchoolGenerator.provider({ count: 8 }), ...DemoChildSchoolRelationGenerator.provider(), ...DemoActivityGeneratorService.provider(), ...DemoActivityEventsGeneratorService.provider({ forNLastYears: 1 }), ...DemoNoteGeneratorService.provider({ minNotesPerChild: 2, maxNotesPerChild: 6, groupNotes: 3, }), ...DemoAserGeneratorService.provider(), ...DemoEducationalMaterialGeneratorService.provider({ minCount: 3, maxCount: 8, }), ...DemoHealthCheckGeneratorService.provider(), ...DemoHistoricalDataGenerator.provider({ minCountAttributes: 2, maxCountAttributes: 5, }), ...DemoTodoGeneratorService.provider(), ]

src/app/child-dev-project/children/demo-data-generators/fixtures/dropout-types.ts

dropoutTypes
Type : []
Default value : [ // multiple entries for the same value increase its probability $localize`:Dropout type:Finished School or Training`, $localize`:Dropout type:Dropout`, $localize`:Dropout type:Continues Education without project`, $localize`:Dropout type:Moved away`, ]

src/app/core/config/dynamic-components/dynamic-component.decorator.ts

DynamicComponent
Type : unknown
Default value : (_name: string) => (_: ComponentType<any>) => undefined

Decorator to annotate a class that serves as dynamic component A dynamic component can be referenced from the config with the name defined on the decorator.

IMPORTANT: The component also needs to be added to the ...Components list of the respective module.

src/app/features/de-duplication/de-duplication-module.ts

dynamicComponents
Type : unknown[]
Default value : [ [ "BulkMergeRecordsComponent", () => import("./bulk-merge-records/bulk-merge-records.component").then( (c) => c.BulkMergeRecordsComponent, ), ], [ "ReviewDuplicates", () => import("./review-duplicates/review-duplicates.component").then( (c) => c.ReviewDuplicatesComponent, ), ], ]

src/app/features/public-form/public-form.module.ts

dynamicComponents
Type : unknown[]
Default value : [ [ "EditPublicFormColumns", () => import("app/features/public-form/edit-public-form-columns/edit-public-form-columns.component").then( (c) => c.EditPublicFormColumnsComponent, ), ], [ "EditPrefilledValuesComponent", () => import("app/features/public-form/edit-prefilled-values/edit-prefilled-values.component").then( (c) => c.EditPrefilledValuesComponent, ), ], [ "EditPublicformRoute", () => import("app/features/public-form/edit-publicform-route/edit-publicform-route.component").then( (c) => c.EditPublicformRouteComponent, ), ], [ "EditPublicFormRelatedEntitiesComponent", () => import("app/features/public-form/edit-public-form-related-entities/edit-public-form-related-entities.component").then( (c) => c.EditPublicFormRelatedEntitiesComponent, ), ], [ "PublicFormPermissionWarning", () => import("app/features/public-form/public-form-permission-warning/public-form-permission-warning.component").then( (c) => c.PublicFormPermissionWarningComponent, ), ], [ "PublicFormFormatWarning", () => import("app/features/public-form/public-form-format-warning/public-form-format-warning.component").then( (c) => c.PublicFormFormatWarningComponent, ), ], ]
viewConfigs
Type : ViewConfig[]
Default value : [ // List View { _id: "view:" + PublicFormConfig.route, component: "EntityList", config: { entityType: PublicFormConfig.ENTITY_TYPE, columns: ["title", "description", "entity"], filters: [{ id: "entity" }], } as EntityListConfig, }, // Details View { _id: "view:" + PublicFormConfig.route + "/:id", component: "EntityDetails", config: { entityType: PublicFormConfig.ENTITY_TYPE, panels: [ { title: $localize`:PublicFormConfig admin form panel:General Setting`, components: [ { component: "Form", config: { fieldGroups: [ { fields: [ { id: "public_form_format_warning", viewComponent: "PublicFormFormatWarning", }, "route", "title", "description", ], }, { fields: [ { id: "permissions_remark", viewComponent: "DisplayDescriptionOnly", label: $localize`:PublicFormConfig admin form:If you want external people filling this form without logging in, the _Permission System_ also has to allow **"public"** users to create new records of this type.<br> If you are seeing problems submitting the form, please contact your **technical support team**.`, }, "entity", { id: "public_form_permission_warning", viewComponent: "PublicFormPermissionWarning", }, "logo", "showSubmitAnotherButton", ], }, ], }, }, ], }, { title: $localize`:PublicFormConfig admin form panel:Configure Fields`, components: [ { component: "Form", config: { fieldGroups: [ { fields: ["columns"], }, ], }, }, ], }, { title: $localize`:PublicFormConfig admin form panel:Configure Pre-filled Values`, components: [ { component: "Form", config: { fieldGroups: [ { fields: [ { id: "prefilled_description", viewComponent: "DisplayDescriptionOnly", label: $localize`:PublicFormConfig admin form:You can configure some fields to be always be set to a certain value when this form is submitted. For example, make a "status" field always be set to "new" so that you can easily filter the new records submitted by external users; or make a "signed up on" date field to always show the current date. If you add the same field(s) in the "Configure Fields" section to show to the user, this pre-filled value can be changed by the person filling the form.`, }, "prefilled", { id: "linked_entities_description", viewComponent: "DisplayDescriptionOnly", label: $localize`:PublicFormConfig admin form:**Collect replies of this form linked to individual records**<br> <br>You can use forms with a special "magic link" to collect responses from participants that are already registered in your system. By sending out an individual link to each person, the form response(s) from that person can be linked into their profile. For example, you can collect feedback or an evaluation survey and relate each submission to the specific participant or organisation that gave it.<br>The system supports linking to multiple entity types. For example, you can encode IDs of a person and activity in the magic link to collect feedback for that specific context. To set this up, select multiple fields below. Currently, such multi-ID URLs need to be generated outside of this system, however.`, }, "linkedEntities", ], }, ], }, }, ], }, ], } as EntityDetailsConfig, }, ]

src/app/features/skill/skill.module.ts

dynamicComponents
Type : unknown[]
Default value : [ [ "EditExternalProfileLink", () => import("./link-external-profile/edit-external-profile-link.component").then( (c) => c.EditExternalProfileLinkComponent, ), ], [ "BulkLinkExternalProfiles", () => import("./bulk-link-external-profiles/bulk-link-external-profiles.component").then( (c) => c.BulkLinkExternalProfilesComponent, ), ], ]

src/app/features/template-export/template-export.module.ts

dynamicComponents
Type : unknown[]
Default value : [ [ "EditTemplateExportFile", () => import("./template-export-file-datatype/edit-template-export-file.component").then( (c) => c.EditTemplateExportFileComponent, ), ], ]
viewConfigs
Type : ViewConfig[]
Default value : [ // List View { _id: "view:" + TemplateExport.route, component: "EntityList", config: { entityType: TemplateExport.ENTITY_TYPE, columns: ["title", "description", "applicableForEntityTypes"], filters: [{ id: "applicableForEntityTypes" }], } as EntityListConfig, }, // Details View { _id: "view:" + TemplateExport.route + "/:id", component: "EntityDetails", config: { entityType: TemplateExport.ENTITY_TYPE, panels: [ { components: [ { component: "Form", config: { fieldGroups: [ { fields: [ "title", "description", "applicableForEntityTypes", "arrayReport", ], }, { fields: [ { id: "template_explanation", viewComponent: "DisplayDescriptionOnly", label: $localize`:TemplateExport:Upload a specially prepared template file here. The file can contain placeholders that will be replaced with actual data when a file is generated for a selected record. For example {d.name} will be replaced with the value in the "name" field of the given record. See the documentation of the [carbone system](https://carbone.io/documentation.html#substitutions) for more information. The placeholder keys must match the field "Field ID" of the record data structure in Aam Digital. You can find this in the Admin UI form builder (Edit Data Structure -> Details View) and edit a specific field to view its details. In addition to the selected record, you can also use fields of the currently logged-in user's own record by prefixing them with "c.user." (e.g. {c.user.name}). This works both in the template file and in the file name pattern. Template files can be in most office document formats (odt, docx, ods, xlsx, odp, pptx) or PDF.`, }, "templateFile", "targetFileName", ], }, ], }, }, ], }, ], } as EntityDetailsConfig, }, ]

src/app/features/todos/todos.module.ts

dynamicComponents
Type : unknown[]
Default value : [ [ "TodosRelatedToEntity", () => import("./todos-related-to-entity/todos-related-to-entity.component").then( (c) => c.TodosRelatedToEntityComponent, ), ], [ "TodosDashboard", () => import("./todos-dashboard/todos-dashboard.component").then( (c) => c.TodosDashboardComponent, ), ], [ "EditRecurringInterval", () => import("./recurring-interval/edit-recurring-interval/edit-recurring-interval.component").then( (c) => c.EditRecurringIntervalComponent, ), ], [ "DisplayRecurringInterval", () => import("./recurring-interval/display-recurring-interval/display-recurring-interval.component").then( (c) => c.DisplayRecurringIntervalComponent, ), ], [ "EditTodoCompletion", () => import("./todo-completion/edit-todo-completion/edit-todo-completion.component").then( (c) => c.EditTodoCompletionComponent, ), ], [ "DisplayTodoCompletion", () => import("./todo-completion/display-todo-completion/display-todo-completion.component").then( (c) => c.DisplayTodoCompletionComponent, ), ], [ "TodosDashboardSettings", () => import("./todos-dashboard-settings.component/todos-dashboard-settings.component").then( (c) => c.TodosDashboardSettingsComponent, ), ], ]

src/app/core/basic-datatypes/configurable-enum/configurable-enum.types.ts

EMPTY
Type : ConfigurableEnumValue
Default value : { id: "", label: "", }

src/app/core/filter/filters/filters.ts

EMPTY_FILTER_OPTION_KEY
Type : string
Default value : "__empty__"

src/app/core/admin/admin-role-permissions/role-details/admin-role-details.component.ts

emptyModel
Type : unknown
Default value : (): MatrixModel => ({ rows: [], unsupportedRules: [] })

fresh empty matrix model; a factory (not a shared const) so callers can never alias a mutable object

src/app/core/permissions/ability/testing-entity-ability-factory.ts

entityAbilityFactory
Type : unknown
Default value : () => { let ability = new EntityAbility(); ability.update([{ subject: "all", action: "manage" }]); return ability; }

src/app/utils/storybook-base.module.ts

entityFormStorybookDefaultParameters
Type : object
Default value : { controls: { exclude: ["_columns", "_cols", "enumValueToString"], }, }

src/app/core/entity/database-entity.decorator.ts

entityRegistry
Type : unknown
Default value : new EntityRegistry((key, constructor) => { if (!(new constructor() instanceof Entity)) { throw Error( `Tried to register an entity-type that is not a subclass of Entity\n` + `type: ${key}; constructor: ${constructor}`, ); } })

src/environments/environment.prod.ts

environment
Type : object
Default value : { production: true, appVersion: "0.0.0", // replaced automatically during docker build repositoryId: "Aam-Digital/ndb-core", // add via config.json overwrite. Default DSN value will be removed in future remoteLoggingDsn: "https://bd6aba79ca514d35bb06a4b4e0c2a21e@sentry.io/1242399", demo_mode: true, session_type: SessionType.mock, webmaster_email: undefined, userAdminApi: undefined, realm: undefined, clientId: undefined, DB_PROXY_PREFIX: "/db", API_PROXY_PREFIX: "/api", notificationsConfig: undefined, SaaS: false, userSupportEnabled: false, use_indexeddb_adapter: false, translationsCdnUrl: "https://aam-digital.github.io/ndb-core/locale", default_data_source: undefined as DataSourceType | undefined, session_type_choice: true, }

see environment.ts for explanations

src/environments/environment.ts

environment
Type : object
Default value : { production: false, appVersion: "0.0.0", // replaced automatically during docker build repositoryId: "Aam-Digital/ndb-core", remoteLoggingDsn: undefined, // only set for production mode in environment.prod.ts demo_mode: true, session_type: SessionType.mock, /** Contact email for the webmaster/operator of this instance, used e.g. as Nominatim usage-policy email. Set via config.json on production. */ webmaster_email: undefined, /** Keycloak API for user management */ userAdminApi: undefined, // loaded from `assets/keycloak.json` during bootstrap /** Keycloak realm for user management */ realm: undefined, // loaded from `assets/keycloak.json` during bootstrap /** Keycloak client id of the app (used e.g. for the "back to application" link in action emails) */ clientId: undefined, // loaded from `assets/keycloak.json` during bootstrap /** Path for the reverse proxy that forwards to the database - configured in `default.conf` */ DB_PROXY_PREFIX: "/db", /** Path for the reverse proxy that forwards to backend services APIs - configured in `default.conf` */ API_PROXY_PREFIX: "/api", /** see FirebaseConfiguration and assets/firebase-config.json */ notificationsConfig: undefined, /** Whether the system is hosted Software-as-a-Service, therefore enabling subscription-related UI */ SaaS: true, /** Has the system a subscription with access to personal user support? */ userSupportEnabled: false, /** * Use the newer "indexeddb" PouchDB adapter instead of the legacy "idb" adapter. * When false (default), the old adapter is used. Set to true via config.json * to opt into the new adapter for gradual rollout. */ use_indexeddb_adapter: false, /** CDN URL for loading translation files at runtime. Empty string disables CDN loading. */ translationsCdnUrl: "https://aam-digital.github.io/ndb-core/locale", /** * Default data source used for all lists in online-only mode (see session_type). * Set to "in-memory" via config.json to load all records of a list upfront, * instead of the default of paging through the database query. * ("paginated" is therefore redundant - it is already the online-only default.) * An explicit `dataSource` in a list's config takes precedence over this default. * * This has no effect outside of online-only mode: the paginated data source * cannot query the local database, so synced sessions always load records upfront. */ default_data_source: undefined as DataSourceType | undefined, /** * Whether users are allowed to choose between synced and online-only mode on the login page. * When false, the toggle is hidden and the session_type configured here is enforced. * Defaults to true (users can choose). */ session_type_choice: true, }

Central environment that allows to configure differences between a "dev" and a "prod" build. For deployments, the assets/config.json can be used to override these settings as well.

The file contents for the current environment will overwrite these during build. The build system defaults to the dev environment which uses environment.ts, but if you do ng build --env=prod then environment.prod.ts will be used instead. The list of which env maps to which file can be found in .angular-cli.json.

src/app/core/database/pouchdb/remote-pouch-database.ts

EXPECTED_4XX_STATUSES
Type : number[]
Default value : [ HttpStatusCode.Unauthorized, HttpStatusCode.Forbidden, HttpStatusCode.NotFound, ]

4XX statuses that occur during normal operation (and are handled by callers or the auth layer), so they are not reported to remote logging.

src/app/core/demo-data/faker.ts

faker
Type : unknown
Default value : new CustomFaker({ locale: [en_IN, en], seed: 1 })

(Extended) faker module

src/app/features/file/file-components.ts

fileComponents
Type : ComponentTuple[]
Default value : [ [ "EditFile", () => import("./edit-file/edit-file.component").then( (c) => c.EditFileComponent, ), ], [ "ViewFile", () => import("./view-file/view-file.component").then( (c) => c.ViewFileComponent, ), ], ]

src/app/core/common-components/entities-table/data-source/paginated-data-source.ts

FULL_LOAD_PAGE_SIZE
Type : number
Default value : 500

Number of documents fetched per request when loading the complete dataset (see PaginatedDataSource.getAllData).

src/app/child-dev-project/children/model/genders.ts

genders
Type : ConfigurableEnumValue[]
Default value : enumJson.values

src/app/features/location/geo.service.ts

GERMAN_ADDRESS_FORMAT_COUNTRY
Type : string
Default value : "de"

Country whose addresses are written as "Street 12, 12345 City", the format GeoService.reformatDisplayName produces.

src/app/child-dev-project/children/demo-data-generators/health-check/height-weight.ts

heightRangeForAge
Type : unknown
Default value : new Map<number, any>([ [2, { min: 78, max: 91 }], [2.5, { min: 83, max: 97 }], [3, { min: 86, max: 101 }], [3.5, { min: 89, max: 105 }], [4, { min: 93, max: 109 }], [4.5, { min: 96, max: 113 }], [5, { min: 99, max: 117 }], [5.5, { min: 102, max: 121 }], [6, { min: 105, max: 125 }], [6.5, { min: 108, max: 129 }], [7, { min: 111, max: 132 }], [7.5, { min: 114, max: 136 }], [8, { min: 116, max: 138 }], [8.5, { min: 119, max: 142 }], [9, { min: 121, max: 145 }], [9.5, { min: 123, max: 148 }], [10, { min: 125, max: 150 }], [10.5, { min: 127, max: 154 }], [11, { min: 130, max: 157 }], [11.5, { min: 133, max: 161 }], [12, { min: 136, max: 164 }], [12.5, { min: 140, max: 167 }], [13, { min: 144, max: 170 }], [13.5, { min: 146, max: 171 }], [14, { min: 148, max: 172 }], [14.5, { min: 148, max: 173 }], [15, { min: 150, max: 174 }], [15.5, { min: 152, max: 174 }], [16, { min: 154, max: 175 }], [16.5, { min: 156, max: 176 }], [17, { min: 158, max: 177 }], [17.5, { min: 158, max: 177 }], [18, { min: 158, max: 177 }], [18.5, { min: 158, max: 177 }], ])
weightRangeForAge
Type : unknown
Default value : new Map<number, any>([ [2, { min: 10, max: 15 }], [2.5, { min: 10, max: 16 }], [3, { min: 11, max: 17 }], [3.5, { min: 11, max: 19 }], [4, { min: 12, max: 20 }], [4.5, { min: 13, max: 22 }], [5, { min: 14, max: 24 }], [5.5, { min: 15, max: 26 }], [6, { min: 15, max: 28 }], [6.5, { min: 16, max: 30 }], [7, { min: 17, max: 32 }], [7.5, { min: 18, max: 35 }], [8, { min: 19, max: 38 }], [8.5, { min: 20, max: 40 }], [9, { min: 21, max: 44 }], [9.5, { min: 22, max: 47 }], [10, { min: 23, max: 50 }], [10.5, { min: 25, max: 54 }], [11, { min: 26, max: 58 }], [11.5, { min: 28, max: 61 }], [12, { min: 29, max: 65 }], [12.5, { min: 31, max: 68 }], [13, { min: 33, max: 71 }], [13.5, { min: 34, max: 74 }], [14, { min: 36, max: 77 }], [14.5, { min: 38, max: 79 }], [15, { min: 40, max: 80 }], [15.5, { min: 42, max: 85 }], [16, { min: 44, max: 90 }], [16.5, { min: 46, max: 95 }], [17, { min: 48, max: 100 }], [17.5, { min: 48, max: 100 }], [18, { min: 48, max: 100 }], [18.5, { min: 48, max: 100 }], ])

src/app/features/change-history/change-history-normalize.ts

HIDDEN_FIELDS
Type : unknown
Default value : new Set([ "_id", "_rev", "_revisions", "created", "updated", ])

Doc fields that are internal/metadata and never shown as user-facing field changes.

src/app/core/common-components/fa-dynamic-icon/fa-icon-utils.ts

iconAliases
Type : unknown
Default value : new Map<string, IconDefinition>([ ["calendar-check-o", faCalendarCheck], ["file-text", faFileAlt], ["question", faQuestionCircle], ["line-chart", faChartLine], ["calendar", faCalendarAlt], ["users", faUsers], ])

A map to prevent old configs from breaking.

resolveIconDefinition
Type : unknown
Default value : ( icon: string | null | undefined, iconLibrary: FaIconLibrary, ): IconDefinition | undefined => { if (!icon) { return undefined; } const trimmedIcon = icon.trim(); if (!trimmedIcon) { return undefined; } const aliasDefinition = iconAliases.get(trimmedIcon); if (aliasDefinition) { return aliasDefinition; } const iconAndDef = trimmedIcon.split(" "); if (iconAndDef.length === 1) { return iconLibrary.getIconDefinition("fas", trimmedIcon as IconName); } return iconLibrary.getIconDefinition( iconAndDef[0] as IconPrefix, iconAndDef[1] as IconName, ); }

src/app/features/location/map-utils.ts

iconDefault
Type : unknown
Default value : L.icon({ iconRetinaUrl, iconUrl, shadowUrl, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], tooltipAnchor: [16, -28], shadowSize: [41, 41], })
iconRetinaUrl
Type : string
Default value : "assets/marker-icon-2x.png"
iconUrl
Type : string
Default value : "assets/marker-icon.png"
shadowUrl
Type : string
Default value : "assets/marker-shadow.png"

src/app/core/import/import/import-sample-raw-data.ts

IMPORT_SAMPLE_ADDITIONAL_ACTIONS
Type : AdditionalImportAction[]
Default value : [ /*{ type: "School", id: IMPORT_SAMPLE_LINKABLE_DATA.find((e) => e.getType() === "School").getId( true, ), }, { type: "RecurringActivity", id: IMPORT_SAMPLE_LINKABLE_DATA.find( (e) => e.getType() === "RecurringActivity", ).getId(), },*/ ]
IMPORT_SAMPLE_COLUMN_MAPPING
Type : ColumnMapping[]
Default value : Object.keys( IMPORT_SAMPLE_RAW_DATA[0], ).map((k) => ({ column: k, }))
IMPORT_SAMPLE_LINKABLE_DATA
Type : Entity[]
Default value : [ Object.assign(createEntityOfType("School"), { name: "Sample School" }), Object.assign(createEntityOfType("School"), { name: "ABCD School" }), Object.assign(createEntityOfType("RecurringActivity"), { title: "Activity X", }), Object.assign(createEntityOfType("RecurringActivity"), { title: "Activity Y", }), ]
IMPORT_SAMPLE_PREVIOUS_IMPORTS
Type : ImportMetadata[]
Default value : [ ImportMetadata.create({ created: { by: TEST_USER, at: new Date("2022-12-27") }, createdEntities: ["1", "2", "3"], config: { entityType: "Child", columnMapping: IMPORT_SAMPLE_COLUMN_MAPPING, }, }), ImportMetadata.create({ created: { by: TEST_USER, at: new Date("2023-01-04") }, createdEntities: ["1", "3"], config: { entityType: "School", columnMapping: [] }, }), ]
IMPORT_SAMPLE_RAW_DATA
Type : any[]
Default value : [ { name: "John Doe", birthDate: "2001-01-31", gender: "M", remarks: "foo bar", }, { name: "Jane Doe", birthDate: "2001-01-31", gender: "F", remarks: "abcde", }, ]

Sample raw data that can be used in Storybook and tests.

src/app/core/import/import.module.ts

importComponents
Type : ComponentTuple[]
Default value : [ [ "Import", () => import("./import/import.component").then((c) => c.ImportComponent), ], [ "DateImportConfig", () => import("../basic-datatypes/date/date-import-config/date-import-config.component").then( (c) => c.DateImportConfigComponent, ), ], [ "DateImportDialog", () => import("../basic-datatypes/date/date-import-config/date-import-dialog.component").then( (c) => c.DateImportDialogComponent, ), ], [ "DiscreteImportConfig", () => import("../basic-datatypes/discrete/discrete-import-config/discrete-import-config.component").then( (c) => c.DiscreteImportConfigComponent, ), ], [ "DiscreteImportDialog", () => import("../basic-datatypes/discrete/discrete-import-config/discrete-import-dialog.component").then( (c) => c.DiscreteImportDialogComponent, ), ], [ "EntityImportConfig", () => import("../basic-datatypes/entity/entity-import-config/entity-import-config.component").then( (c) => c.EntityImportConfigComponent, ), ], ]

src/app/child-dev-project/notes/dashboard-widgets/important-notes-dashboard/important-notes-index.service.ts

INDEX_ID_PREFIX
Type : string
Default value : "importantNotesDashboard"
VIEW_NAME
Type : string
Default value : "importantNotes"
WARNING_LEVEL_ENUM_ID
Type : string
Default value : "warning-levels"

src/app/features/dashboard-widgets/birthday-dashboard-widget/birthday-dashboard/birthday-dashboard-index.service.ts

INDEX_ID_PREFIX
Type : string
Default value : "birthdayDashboard"
VIEW_NAME
Type : string
Default value : "birthday"

src/app/child-dev-project/notes/model/interaction-type.interface.ts

INTERACTION_TYPE_CONFIG_ID
Type : string
Default value : "interaction-type"

ID of the Note category ConfigurableEnumValue in the config database.

src/app/core/admin/admin-role-permissions/role-permissions.service.ts

INTERNAL_ROLES
Type : miscellaneous
Default value : [ UserAdminService.ACCOUNT_MANAGER_ROLE, "no-email-2fa", ]

Technical roles that serve a special function in the authentication server (e.g. granting account-management API access, or opting a user out of email 2FA). They must not be deleted from this admin UI, and their description is managed elsewhere, so it stays read-only here. They may still carry additional permission rules like any other role.

ROLES_ADMIN_ROUTE
Type : string
Default value : "/admin/user-roles"

Base route of the role management admin UI, to link to a role's details from elsewhere. Mirrors the "user-roles" paths registered in admin.routing.ts.

src/app/core/session/auth/keycloak/keycloak-auth.service.ts

KEYCLOAK_OPERATION_TIMEOUT_MS
Type : number
Default value : 15_000

Hard upper bound on individual Keycloak network operations (init, token refresh). Picked well above expected RTT but short enough that a hung proxy/upstream surfaces a clear failure to the user.

LOGIN_RETRY_DELAYS_MS
Type : []
Default value : [1_000, 3_000]

Backoff schedule for explicit user-initiated login retries.

TOKEN_MIN_VALIDITY_SECONDS
Type : number
Default value : 30

Minimum remaining lifetime (in seconds) requested when refreshing the token in the background. Matches keycloak-js's updateToken(minValidity) argument.

TOKEN_REFRESH_RETRY_DELAYS_MS
Type : []
Default value : [2_000, 5_000]

Backoff schedule for background token refreshes (OnTokenExpired). Kept short — if the background refresh keeps failing, the next API call's 401 will trigger an explicit login, so there is no point retrying for many seconds and stalling the user's request.

src/app/child-dev-project/children/demo-data-generators/fixtures/languages.ts

languages
Type : []
Default value : [ // multiple entries for the same value increase its probability "Hindi", "Hindi", "Hindi", "Urdu", "Bengali", "Bengali", "", ]

src/bootstrap-reset.ts

LAST_SYNC_KEY_PREFIX
Type : string
Default value : "LAST_SYNC_"

localStorage key prefix under which SyncedPouchDatabase records when a database last completed a sync (one key per database).

RESET_PENDING_KEY
Type : string
Default value : "__RESET_PENDING"

sessionStorage key used to signal that a reset is pending. Set before a page reload; checked on the next bootstrap in runPendingReset.

src/app/utils/media/screen-size-observer.service.ts

LG
Type : string
Default value : "992px"
MD
Type : string
Default value : "768px"
MOBILE_THRESHOLD
Type : ScreenSize
Default value : ScreenSize.sm

The screen size where anything smaller and this size itself is considered mobile while anything strictly larger is considered desktop.

SM
Type : string
Default value : "576px"
XL
Type : string
Default value : "1200px"
XXL
Type : string
Default value : "1400px"

src/app/utils/di-tokens.ts

LOCAL_STORAGE_TOKEN
Type : miscellaneous
Default value : new InjectionToken<Storage>( "Window localStorage object", { providedIn: "root", factory: () => localStorage }, )

Use this instead of referencing localStorage directly.

Tests otherwise have to stub Storage.prototype, which belongs to the worker process rather than the module registry — Vitest's isolate does not undo it, so an unrestored stub leaks into every later spec file and makes unrelated tests read a fake localStorage. Injecting a fake avoids that entirely.

LOCATION_TOKEN
Type : unknown
Default value : new InjectionToken<Location>( "Window location object", )
NAVIGATOR_TOKEN
Type : unknown
Default value : new InjectionToken<Navigator>( "Window navigator object", )
WINDOW_TOKEN
Type : unknown
Default value : new InjectionToken<Window>("Window object")

Use this instead of directly referencing the window object for better testability

src/app/features/location/location-components.ts

locationComponents
Type : ComponentTuple[]
Default value : [ [ "EditLocation", () => import("./edit-location/edit-location.component").then( (c) => c.EditLocationComponent, ), ], [ "ViewLocation", () => import("./view-location/view-location.component").then( (c) => c.ViewLocationComponent, ), ], [ "DisplayDistance", () => import("./view-distance/view-distance.component").then( (c) => c.ViewDistanceComponent, ), ], [ "LocationImportConfig", () => import("./location-import-config/location-import-config.component").then( (c) => c.LocationImportConfigComponent, ), ], ]

src/app/features/location/location-import-config/location-import-config.component.ts

LOOKUP_WARNING_THRESHOLD
Type : number
Default value : 50

src/app/features/location/map-config.ts

MAP_CONFIG_KEY
Type : string
Default value : "appConfig:map"

src/app/core/common-components/entity-form/dynamic-form-validators/permission-condition-validators.ts

MATCH_ACTION
Type : string
Default value : "match"
MATCH_SUBJECT
Type : string
Default value : "PermissionConditionCheck"

src/app/features/matching-entities/matching-entities-components.ts

matchingEntitiesComponents
Type : ComponentTuple[]
Default value : [ [ "MatchingEntities", () => import("./matching-entities/matching-entities.component").then( (c) => c.MatchingEntitiesComponent, ), ], [ "AdminMatchingEntities", () => import("./admin-matching-entities/admin-matching-entities.component").then( (c) => c.AdminMatchingEntitiesComponent, ), ], ]

src/app/child-dev-project/children/demo-data-generators/educational-material/materials.ts

materials
Type : ConfigurableEnumValue[]
Default value : enums.find( (e) => e._id === "ConfigurableEnum:materials", ).values

src/app/child-dev-project/children/demo-data-generators/aser/skill-levels.ts

mathLevels
Type : ConfigurableEnumConfig<SkillLevel>
Default value : enums.find( (e) => e._id === "ConfigurableEnum:math-levels", ).values
readingLevels
Type : ConfigurableEnumConfig<SkillLevel>
Default value : enums.find( (e) => e._id === "ConfigurableEnum:reading-levels", ).values

src/app/core/language/TranslatableMatPaginator.ts

matRangeLabelIntl
Type : unknown
Default value : (page: number, pageSize: number, length: number) => { if (length === 0 || pageSize === 0) { return $localize`:@@paginator.zeroRange:0 in ${length}`; } length = Math.max(length, 0); const startIndex = page * pageSize; // If the start index exceeds the list length, do not try and fix the end index to the end. const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize; return $localize`:@@paginator.rangeOfLabel:${ startIndex + 1 } - ${endIndex} of ${length}`; }

src/app/core/admin/admin-role-permissions/permission-matrix.ts

MATRIX_ACTIONS
Type : EntityActionPermission[]
Default value : [ "read", "create", "update", "delete", "manage", ]

src/app/core/admin/admin-menu/menu-item-for-admin-ui.ts

menuItemTree
Type : FlatTreeAdapter<MenuItemForAdminUi>
Default value : { id: (item) => item.uniqueId, children: (item) => item.subMenu ?? [], withChildren: (item, subMenu) => ({ ...item, subMenu }), }

Edit the menu as a flat, indented list (see flat-tree): every menu item can hold nested sub-items.

src/app/features/inherited-field/inherited-field-config-migration.ts

migrateInheritedFieldConfig
Type : ConfigMigration
Default value : ( key, configPart, ) => { if (key !== "defaultValue" || !configPart?.config) { return configPart; } const config = configPart.config; if (configPart.mode === "inherited-from-referenced-entity") { const newConfig: DefaultValueConfigInheritedField = { sourceReferenceField: config.localAttribute, sourceValueField: config.field, }; return { ...configPart, mode: "inherited-field", config: newConfig, }; } if (configPart.mode === "updated-from-referencing-entity") { const newConfig: DefaultValueConfigInheritedField = { sourceReferenceEntity: config.relatedEntityType, sourceReferenceField: config.relatedReferenceField, sourceValueField: config.relatedTriggerField, valueMapping: config.automatedMapping, }; return { ...configPart, mode: "inherited-field", config: newConfig, }; } return configPart; }

Transform DefaultValueConfigInherited and DefaultValueConfigUpdatedFromReferencingEntity configs to DefaultValueConfigInheritedField.

src/app/features/skill/skill-api/skill-api-mock.ts

mockSkillApi
Type : object
Default value : { getExternalProfiles: (): Observable<ExternalProfileResponseDto> => of({ pagination: { currentPage: 1, pageSize: 5, totalPages: 2, totalElements: 6, }, results: faker.helpers.multiple( () => createSkillApiDummyData(faker.string.numeric()), { count: { min: 0, max: 5 } }, ), }).pipe(delay(faker.number.int({ min: 500, max: 1500 }))), generateDefaultSearchParams: () => ({ fullName: "John Doe", }), getExternalProfileById: (id: string) => of(createSkillApiDummyData(id)).pipe( delay(faker.number.int({ min: 500, max: 1500 })), ), async isSkillApiEnabled() { return false; }, }

src/app/core/basic-datatypes/month/edit-month/edit-month.component.ts

MY_FORMATS
Type : object
Default value : { parse: { dateInput: "YYYY-MM", }, display: { dateInput: "YYYY-MM", monthYearLabel: "YYYY MMM", dateA11yLabel: "LL", monthYearA11yLabel: "YYYY MMMM", }, }

src/app/features/public-form/edit-publicform-route/edit-publicform-route.component.ts

noSpecialUrlChars
Type : ValidatorFn
Default value : (control: AbstractControl) => { const value: string = control.value; if (value && !/^[a-zA-Z\d\-_]+$/.test(value)) { return { pattern: { errorMessage: $localize`The link ID may only contain lowercase letters, digits, hyphens and underscores`, }, }; } return null; }

src/app/core/filter/not-archived-filter.ts

NOT_ARCHIVED_FILTER
Type : object
Default value : { $or: [{ inactive: { $ne: true } }, { inactive: { $exists: false } }], }

Select records that are not archived.

The inactive flag is only written when a record gets archived, so for the vast majority of records the property is missing entirely. A plain { inactive: { $ne: true } } does not reliably match those in a database query, so the missing case is spelled out as its own condition.

src/app/child-dev-project/notes/demo-data/notes_group-stories.ts

noteGroupStories
Type : []
Default value : [ { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_MEETING"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Guardians Meeting`, text: $localize`:Note demo text: Our regular monthly meeting. Find the agenda and minutes in our meeting folder. `, }, { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_MEETING"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Guardians Meeting`, text: $localize`:Note demo text: Our regular monthly meeting. Find the agenda and minutes in our meeting folder. `, }, { category: defaultInteractionTypes.find((t) => t.id === "COACHING_CLASS"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Children Meeting`, text: $localize`:Note demo text: Our regular monthly meeting. Find the agenda and minutes in our meeting folder. `, }, { category: defaultInteractionTypes.find((t) => t.id === "COACHING_CLASS"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Children Meeting`, text: $localize`:Note demo text: Our regular monthly meeting. Find the agenda and minutes in our meeting folder. `, }, { category: defaultInteractionTypes.find((t) => t.id === "COACHING_CLASS"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Drug Prevention Workshop`, text: $localize`:Note demo text: Expert conducted a two day workshop on drug prevention. `, }, ]

src/app/child-dev-project/notes/demo-data/notes_individual-stories.ts

noteIndividualStories
Type : []
Default value : [ { category: defaultInteractionTypes.find((t) => t.id === "VISIT"), warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: $localize`:Note demo subject:Mother sick`, text: $localize`:Note demo text: Visited family after we heard that mother is seriously ill. She cannot get up. Children are taking care of housework. Told her to see doctor. We should follow up next week. `, }, { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_TALK"), warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: $localize`:Note demo subject:Discussed school change`, text: $localize`:Note demo text: Discussed future of the child with the parents. They agree that changing school can be a good option. Will discuss further together with the child. `, }, { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_TALK"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Follow up for school absence`, text: $localize`:Note demo text: Called to ask for reason about absence. Mother made excuses but promised to send the child tomorrow. `, }, { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_TALK"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Absent because ill`, text: $localize`:Note demo text: Mother has called in the morning. Child cannot come to class because of fever. `, }, { category: defaultInteractionTypes.find((t) => t.id === "GUARDIAN_TALK"), warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: $localize`:Note demo subject:Absence without information`, text: $localize`:Note demo text: Child was not in school whole last week again. When calling the mother she didn't know about it. Need to follow up urgently to discuss with the child and the guardians. `, }, { category: defaultInteractionTypes.find((t) => t.id === "VISIT"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:School is happy about progress`, text: $localize`:Note demo text: Visited the school and talked to the class teacher and principal. They are happy about the progress and behaviour. `, }, { category: defaultInteractionTypes.find((t) => t.id === "VISIT"), warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: $localize`:Note demo subject:Needs to work more for school`, text: $localize`:Note demo text: Discussed the child's progress with coaching teacher. He is still a weak student and needs more support. We should consider arranging an extra class for him. Discuss next social worker meeting. `, }, { category: defaultInteractionTypes.find((t) => t.id === "INCIDENT"), warningLevel: warningLevels.find((level) => level.id === "URGENT"), subject: $localize`:Note demo subject:Fight at school`, text: $localize`:Note demo text: Principal called us today. Our student got into a fight and was suspended for a week. Need to follow up with the child and discuss the matter. `, }, { category: defaultInteractionTypes.find((t) => t.id === "INCIDENT"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Special help for family`, text: $localize`:Note demo text: Since the father has lost his job the family is struggling to survive. After home visits and discussion in our team we decided to refer them to a special support programme. `, }, { category: defaultInteractionTypes.find((t) => t.id === "INCIDENT"), warningLevel: warningLevels.find((level) => level.id === "OK"), subject: $localize`:Note demo subject:Chance to repeat class`, text: $localize`:Note demo text: Child has failed this school year as she did not go to school regularly. After a long discussion with the child and her parents we agreed to support her to repeat the class and she promised to attend school regularly. `, }, { category: defaultInteractionTypes.find((t) => t.id === "NOTE"), warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: $localize`:Note demo subject:Distracted in class`, text: $localize`:Note demo text: Teacher has let us know that he is very unfocused during class these days. Discussed with him - there are a lot of problems in the family currently. `, }, { category: defaultInteractionTypes.find((t) => t.id === "NOTE"), warningLevel: warningLevels.find((level) => level.id === "WARNING"), subject: $localize`:Note demo subject:Disturbing class`, text: $localize`:Note demo text: She refused to listen to the teacher was disturbing the class. Did counselling session with her. `, }, ]

src/app/child-dev-project/notes/notes-components.ts

notesComponents
Type : ComponentTuple[]
Default value : [ [ "NotesDashboard", () => import("./dashboard-widgets/notes-dashboard/notes-dashboard.component").then( (c) => c.NotesDashboardComponent, ), ], [ "NotesRelatedToEntity", () => import("./notes-related-to-entity/notes-related-to-entity.component").then( (c) => c.NotesRelatedToEntityComponent, ), ], [ "ImportantNotesDashboard", () => import("./dashboard-widgets/important-notes-dashboard/important-notes-dashboard.component").then( (c) => c.ImportantNotesDashboardComponent, ), ], [ "NoteDetails", () => import("./note-details/note-details.component").then( (c) => c.NoteDetailsComponent, ), ], [ "ImportantNotesDashboardSettings", () => import("./dashboard-widgets/important-notes-dashboard-settings.component/important-notes-dashboard-settings.component").then( (c) => c.ImportantNotesDashboardSettingsComponent, ), ], [ "NotesDashboardSettings", () => import("./dashboard-widgets/notes-dashboard-settings.component/notes-dashboard-settings.component").then( (c) => c.NotesDashboardSettingsComponent, ), ], ]

src/app/core/config/dynamic-routing/view-config.interface.ts

PREFIX_VIEW_CONFIG
Type : string
Default value : "view:"

The prefix which is used to find the ViewConfig's in the config file

src/app/features/public-form/public-form-route.ts

PUBLIC_FORM_ROUTE
Type : string
Default value : "public-form"

Top-level route segment under which public (anonymous) forms are served.

Kept in a module without imports of its own, because the app bootstrap needs this value (see bootstrap-environment.ts) and must not load the public form components and their dependencies while doing so.

src/app/features/public-form/public-form-routing.ts

publicFormRoutes
Type : Routes
Default value : [ { path: "form/:id", component: PublicFormComponent, }, { path: "submission-success", component: SubmissionSuccessComponent }, ]

src/app/child-dev-project/children/demo-data-generators/observations/rating-answers.ts

ratingAnswers
Type : ConfigurableEnumValue[]
Default value : enumJson.values

src/app/utils/related-entities-default-config.ts

RELATED_ENTITIES_DEFAULT_CONFIGS
Type : Record<string, { entityType: string; columns?: FormFieldConfig[] }>
Default value : { NotesRelatedToEntity: { entityType: "Note", columns: [ { id: "date", visibleFrom: "xs" }, { id: "subject", visibleFrom: "xs" }, { id: "text", visibleFrom: "md" }, { id: "authors", visibleFrom: "md" }, { id: "warningLevel", visibleFrom: "md" }, ], }, TodosRelatedToEntity: { entityType: "Todo", columns: [ { id: "deadline" }, { id: "subject" }, { id: "startDate" }, { id: "assignedTo" }, { id: "description", visibleFrom: "xl" }, { id: "repetitionInterval", visibleFrom: "xl" }, { id: "relatedEntities", hideFromTable: true }, { id: "completed", hideFromForm: true }, ], }, }
RELATED_ENTITY_OVERRIDES
Type : Record<string, Partial<RelatedEntitiesComponentConfig>>
Default value : { EducationalMaterial: { component: "RelatedEntitiesWithSummary", }, HistoricalEntityData: { loaderMethod: "HistoricalDataService", }, }

src/app/child-dev-project/children/demo-data-generators/fixtures/religions.ts

religions
Type : []
Default value : [ // multiple entries for the same value increase its probability $localize`:religion:Hindu`, $localize`:religion:Hindu`, $localize`:religion:Hindu`, $localize`:religion:Muslim`, $localize`:religion:Muslim`, $localize`:religion:Christian`, $localize`:religion:Sikh`, "", "", ]

src/app/features/reporting/reporting.module.ts

reportAdminViewConfigs
Type : ViewConfig[]
Default value : [ { _id: "view:" + ReportEntity.route, component: "EntityList", config: { entityType: ReportEntity.ENTITY_TYPE, columns: ["title", "mode", "description"], } as EntityListConfig, }, // Details / edit view { _id: "view:" + ReportEntity.route + "/:id", component: "EntityDetails", config: { entityType: ReportEntity.ENTITY_TYPE, panels: [ { components: [ { component: "Form", config: { fieldGroups: [ { fields: [ { id: "report_explanation", viewComponent: "DisplayDescriptionOnly", label: $localize`:ReportConfig:Configure a report that users can run to generate aggregated statistics or data exports. See [Analyzing data through advanced reports](https://chatwoot.help/hc/aam-digital/articles/1782889956-analyzing-data-through-advanced-reports) for how to set up and use reports.`, }, "title", "mode", "description", "transformations", ], }, { fields: ["reportDefinition"] }, ], }, }, ], }, ], } as EntityDetailsConfig, }, ]

Admin list + details views to manage ReportEntity configs, registered the same way as other "Templates and Forms" entities (e.g. EmailTemplate).

src/app/features/reporting/edit-report-definition/report-definition-ui-node.ts

reportDefinitionTree
Type : FlatTreeAdapter<ReportDefinitionUiNode>
Default value : { id: (node) => node.uniqueId, children: (node) => node.items, withChildren: (node, items) => ({ ...node, items }), }

Edit the definition as a flat, indented list: only groups can hold nested items, queries are always leaves.

src/app/features/reporting/report-config.ts

ReportEntity
Type : unknown
Default value : ReportConfig as EntityConstructor<ReportEntity>

This allows the ReportEntity to also be used as a constructor or in the EntityMapper

src/app/features/reporting/reporting-components.ts

reportingComponents
Type : ComponentTuple[]
Default value : [ [ "Reporting", () => import("./reporting/reporting.component").then( (c) => c.ReportingComponent, ), ], [ "EditReportMode", () => import("./edit-report-mode/edit-report-mode.component").then( (c) => c.EditReportModeComponent, ), ], [ "EditReportPeriodToggle", () => import("./edit-report-period-toggle/edit-report-period-toggle.component").then( (c) => c.EditReportPeriodToggleComponent, ), ], [ "EditSqlQuery", () => import("./edit-sql-query/sql-code-editor.component").then( (c) => c.SqlCodeEditorComponent, ), ], [ "EditReportDefinition", () => import("./edit-report-definition/edit-report-definition.component").then( (c) => c.EditReportDefinitionComponent, ), ], ]

src/app/core/admin/admin.routing.ts

ROLE_MANAGEMENT_ROLES
Type : []
Default value : ["account_manager", ADMIN_APP_ROLE]

src/app/route-target.ts

RouteTarget
Type : unknown
Default value : (_name: string) => (_) => undefined

Marks a class to be the target when routing. Use this by adding the annotation @RouteTarget("...") to a component. The name provided to the annotation can then be used in the configuration.

IMPORTANT: The component also needs to be added to the ...Components list of the respective module.

src/app/core/user/user.routing.ts

routing
Type : ModuleWithProviders<RouterModule>
Default value : RouterModule.forChild(routes)

RoutingModule for UserModule related routes. Separating these routes from the main AppModule routing allows lazy-loading of modules.

src/app/features/reporting/reporting/reporting.component.ts

STALE_THRESHOLD_SECONDS
Type : number
Default value : 60

A shown calculation older than this (seconds) is treated as stale/outdated.

src/app/features/todos/model/demo-todo-generator.service.ts

stories
Type : Partial[]
Default value : [ { subject: $localize`:demo todo record:get signed agreement`, description: $localize`:demo todo record:We have fixed all the details but still have to put it in writing.`, }, { subject: $localize`:demo todo record:follow up`, description: $localize`:demo todo record:Call to follow up on the recent developments.`, }, { subject: $localize`:demo todo record:call family`, description: $localize`:demo todo record:Check about the latest incident.`, }, { subject: $localize`:demo todo record:plan career counselling`, description: $localize`:demo todo record:Personalized plan for the next discussion has to be prepared.`, }, ]

src/app/core/filter/string-filter/string-filter.component.ts

STRING_FILTER_DEBOUNCE_MS
Type : number
Default value : 400

Delay (ms) before a changed search text is applied, so that typing does not trigger a filter update (and, for server-side data sources, a DB request) on every single keystroke.

src/app/core/user/demo-user-generator.service.ts

TEST_USER
Type : string
Default value : "demo"

src/app/features/attendance/display-attendance/display-attendance.component.ts

THRESHOLD_URGENT
Type : number
Default value : 0.6

Thresholds for attendance percentage coloring.

THRESHOLD_WARNING
Type : number
Default value : 0.8

src/app/features/todos/recurring-interval/time-interval.ts

timeunitLabelMap
Type : Map<unitOfTime.Base, string>
Default value : new Map([ ...timeUnitsPrimary.map( (e) => [e.unit, e.label] as [unitOfTime.Base, string], ), // alternative spellings ["year", $localize`:time unit:years`], ["y", $localize`:time unit:years`], ["month", $localize`:time unit:months`], ["m", $localize`:time unit:months`], ["week", $localize`:time unit:weeks`], ["w", $localize`:time unit:weeks`], ["day", $localize`:time unit:days`], ["d", $localize`:time unit:days`], ])
timeUnitsPrimary
Type : literal type[]
Default value : [ { unit: "days", label: $localize`:time unit:days` }, { unit: "weeks", label: $localize`:time unit:weeks` }, { unit: "months", label: $localize`:time unit:months` }, { unit: "years", label: $localize`:time unit:years` }, ]

src/app/features/todos/model/todo-filters.ts

TODO_COMPLETED_FILTER
Type : unknown
Default value : { $and: [{ completed: { $exists: true } }, { completed: { $ne: null } }], } as DataFilter<Todo>

Select Todo records that have been completed.

TODO_NOT_COMPLETED_FILTER
Type : unknown
Default value : { $or: [{ completed: { $exists: false } }, { completed: { $eq: null } }], } as DataFilter<Todo>

Select Todo records that have not been completed.

TodoService.uncompleteTodo resets completed to null instead of removing the property, so records without the property and records holding null both have to be matched. Each branch is an object (rather than a plain null value) so that the filter can also be used as the initial filter of a list, where FilterService inspects it to prefill new records.

src/app/core/logging/http-response-logging.ts

UNEXPECTED_STATUS_NAMES
Type : miscellaneous
Default value : { [HttpStatusCode.BadRequest]: "bad request", [HttpStatusCode.PayloadTooLarge]: "payload too large", [HttpStatusCode.TooManyRequests]: "too many requests", }

Names for the response statuses that are reported to remote monitoring.

Monitoring groups a reported message by its normalized text, and that normalization masks numbers (see fingerprintKey), so a status interpolated as a number would collapse every unexpected response into one issue - the mixed bucket this exists to prevent. In AAM-DIGITAL-77H a rejected write, a malformed query and a replication checkpoint read all shared one title, and none of them could be told apart or triaged. Naming the status keeps the message text static (as the logging conventions require) while giving each root cause its own issue and a title that says what happened.

Only statuses that plausibly occur are listed, because each one here should mean a different response:

  • 400 a malformed request (a bad query, or a proxy mangling the url)
  • 413 a payload over the reverse proxy's limit, e.g. a large attachment
  • 429 throttling Anything else shares one bucket via unexpectedResponseMessage and is still reported with its numeric status in the logged context.

src/app/core/common-components/entity-form/unique-property-validator/unique-property-validator.ts

UNIQUE_PROPERTY_ERROR_KEY
Type : string
Default value : "uniqueProperty"

src/app/core/analytics/usage-analytics-config.ts

USAGE_ANALYTICS_CONFIG_ID
Type : string
Default value : "appConfig:usage-analytics"

src/app/features/email-client/email-client.module.ts

viewConfigs
Type : ViewConfig[]
Default value : [ { _id: "view:" + EmailTemplate.route, component: "EntityList", config: { entityType: EmailTemplate.ENTITY_TYPE, columns: ["subject", "body", "availableForEntityTypes", "category"], } as EntityListConfig, }, // Details View { _id: "view:" + EmailTemplate.route + "/:id", component: "EntityDetails", config: { entityType: EmailTemplate.ENTITY_TYPE, panels: [ { components: [ { component: "Form", config: { fieldGroups: [ { fields: ["subject", "body"], }, { fields: ["availableForEntityTypes", "category"], }, ], }, }, ], }, ], } as EntityDetailsConfig, }, ]

src/app/child-dev-project/warning-level.ts

warningLevels
Type : Ordering.EnumValue[]
Default value : enumJson.values

results matching ""

    No results matching ""